From a9801766e5e3e58d693d86f28b96ad7a5612eed6 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 17 Nov 2010 22:14:55 +0000 Subject: [PATCH 01/19] * PrivateKeyFile: Speedups and better messages --- .../java/src/net/i2p/data/PrivateKeyFile.java | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java index dc445a37ae..eab03576da 100644 --- a/core/java/src/net/i2p/data/PrivateKeyFile.java +++ b/core/java/src/net/i2p/data/PrivateKeyFile.java @@ -80,10 +80,13 @@ public class PrivateKeyFile { if (args[0].equals("-n")) { // Cert constructor generates a null cert pkf.setCertType(Certificate.CERTIFICATE_TYPE_NULL); + System.out.println("New destination with null cert is:"); } else if (args[0].equals("-u")) { pkf.setCertType(99); + System.out.println("New destination with unknown cert is:"); } else if (args[0].equals("-x")) { pkf.setCertType(Certificate.CERTIFICATE_TYPE_HIDDEN); + System.out.println("New destination with hidden cert is:"); } else if (args[0].equals("-h")) { int hashEffort = HASH_EFFORT; if (args.length == 3) @@ -91,12 +94,13 @@ public class PrivateKeyFile { System.out.println("Estimating hashcash generation time, stand by..."); System.out.println(estimateHashCashTime(hashEffort)); pkf.setHashCashCert(hashEffort); + System.out.println("New destination with hashcash cert is:"); } else if (args.length == 3 && args[0].equals("-s")) { // Sign dest1 with dest2's Signing Private Key PrivateKeyFile pkf2 = new PrivateKeyFile(args[2]); pkf.setSignedCert(pkf2); + System.out.println("New destination with signed cert is:"); } - System.out.println("New signed destination is:"); System.out.println(pkf); pkf.write(); verifySignature(d); @@ -318,23 +322,56 @@ public class PrivateKeyFile { byte[] data = new byte[len]; System.arraycopy(d.getPublicKey().getData(), 0, data, 0, PublicKey.KEYSIZE_BYTES); System.arraycopy(d.getSigningPublicKey().getData(), 0, data, PublicKey.KEYSIZE_BYTES, SigningPublicKey.KEYSIZE_BYTES); - Signature sig = new Signature(d.getCertificate().getPayload()); + Signature sig = new Signature(); + byte[] payload = d.getCertificate().getPayload(); + Hash signerHash = null; + if (payload == null) { + System.out.println("Bad signed cert - no payload"); + return false; + } else if (payload.length == Signature.SIGNATURE_BYTES) { + sig.setData(payload); + } else if (payload.length == Certificate.CERTIFICATE_LENGTH_SIGNED_WITH_HASH) { + byte[] pl = new byte[Signature.SIGNATURE_BYTES]; + System.arraycopy(payload, 0, pl, 0, Signature.SIGNATURE_BYTES); + sig.setData(pl); + byte[] hash = new byte[Hash.HASH_LENGTH]; + System.arraycopy(payload, Signature.SIGNATURE_BYTES, hash, 0, Hash.HASH_LENGTH); + signerHash = new Hash(hash); + System.out.println("Destination is signed by " + Base32.encode(hash) + ".b32.i2p"); + } else { + System.out.println("Bad signed cert - length = " + payload.length); + return false; + } String[] filenames = new String[] {"privatehosts.txt", "userhosts.txt", "hosts.txt"}; + int tried = 0; for (int i = 0; i < filenames.length; i++) { Properties hosts = new Properties(); try { File f = new File(filenames[i]); if ( (f.exists()) && (f.canRead()) ) { DataHelper.loadProps(hosts, f, true); + int sz = hosts.size(); + if (sz > 0) { + tried += sz; + if (signerHash == null) + System.out.println("Attempting to verify using " + sz + " hosts, this may take a while"); + } for (Iterator iter = hosts.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); String s = (String) entry.getValue(); Destination signer = new Destination(s); - if (checkSignature(sig, data, signer.getSigningPublicKey())) { - System.out.println("Good signature from: " + entry.getKey()); - return true; + // make it go faster if we have the signerHash hint + if (signerHash == null || signer.calculateHash().equals(signerHash)) { + if (checkSignature(sig, data, signer.getSigningPublicKey())) { + System.out.println("Good signature from: " + entry.getKey()); + return true; + } + if (signerHash != null) { + System.out.println("Bad signature from: " + entry.getKey()); + // could probably return false here but keep going anyway + } } } } @@ -342,7 +379,10 @@ public class PrivateKeyFile { } // not found, continue to the next file } - System.out.println("No valid signer found"); + if (tried > 0) + System.out.println("No valid signer found"); + else + System.out.println("No addressbooks found to valididate signer"); return false; } From 995c736a71fc5622bf7186bba28492c051d3886f Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 17 Nov 2010 22:15:45 +0000 Subject: [PATCH 02/19] peers.jsp fixups --- .../router/transport/TransportManager.java | 7 +++- .../router/transport/udp/UDPTransport.java | 38 ++++++++++++------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 243c76237b..cf21af11d9 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -492,7 +492,7 @@ public class TransportManager implements TransportEventListener { t.renderStatusHTML(out, urlBase, sortFlags); } - if (_transports.size() > 0) { + if (!_transports.isEmpty()) { out.write(getTransportsLegend()); } @@ -516,6 +516,11 @@ public class TransportManager implements TransportEventListener { private final String getTransportsLegend() { StringBuilder buf = new StringBuilder(1024); + buf.append("

").append(_("Help")).append("

") + .append(_("Your transport connection limits are automatically set based on your configured bandwidth.")) + .append('\n') + .append(_("To override these limits, add the settings i2np.ntcp.maxConnections=nnn and i2np.udp.maxConnections=nnn on the advanced configuration page.")) + .append("

\n"); buf.append("

").append(_("Definitions")).append("

" + "

").append(_("Peer")).append(": ").append(_("The remote peer, identified by router hash")).append("
\n" + "").append(_("Dir")).append(": " + 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 f0e9c9e2e9..dc0790ac48 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1978,15 +1978,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // buf.append(' ').append(_context.blocklist().toStr(ip)); buf.append(""); - long idleIn = (now-peer.getLastReceiveTime())/1000; - long idleOut = (now-peer.getLastSendTime())/1000; - if (idleIn < 0) idleIn = 0; - if (idleOut < 0) idleOut = 0; + long idleIn = Math.max(now-peer.getLastReceiveTime(), 0); + long idleOut = Math.max(now-peer.getLastSendTime(), 0); buf.append(""); - buf.append(DataHelper.formatDuration2(1000 * idleIn)); + buf.append(DataHelper.formatDuration2(idleIn)); buf.append("&thinsp/ "); - buf.append(DataHelper.formatDuration2(1000 * idleOut)); + buf.append(DataHelper.formatDuration2(idleOut)); buf.append(""); int recvBps = (idleIn > 2 ? 0 : peer.getReceiveBps()); @@ -2010,7 +2008,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority buf.append(""); buf.append(""); - buf.append(DataHelper.formatDuration2(peer.getClockSkew())); + long skew = peer.getClockSkew(); + buf.append(formatDuration3(peer.getClockSkew())); buf.append(""); offsetTotal = offsetTotal + peer.getClockSkew(); @@ -2032,15 +2031,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority int rto = peer.getRTO(); buf.append(""); - buf.append(rtt); + buf.append(DataHelper.formatDuration2(rtt)); buf.append(""); buf.append(""); - buf.append(peer.getRTTDeviation()); + buf.append(DataHelper.formatDuration2(peer.getRTTDeviation())); buf.append(""); buf.append(""); - buf.append(rto); + buf.append(DataHelper.formatDuration2(rto)); buf.append(""); buf.append(""); @@ -2104,19 +2103,19 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // buf.append("


\n"); buf.append(" ").append(_("SUMMARY")).append("" + ""); - buf.append(formatKBps(bpsIn)).append("thinsp;/ ").append(formatKBps(bpsOut)); + buf.append(formatKBps(bpsIn)).append(" / ").append(formatKBps(bpsOut)); long x = numPeers > 0 ? uptimeMsTotal/numPeers : 0; buf.append("" + "").append(DataHelper.formatDuration2(x)); x = numPeers > 0 ? offsetTotal/numPeers : 0; - buf.append("").append(DataHelper.formatDuration2(x)).append("\n" + + buf.append("").append(formatDuration3(x)).append("\n" + ""); buf.append(numPeers > 0 ? cwinTotal/(numPeers*1024) + "K" : "0K"); buf.append(" \n" + ""); - buf.append(numPeers > 0 ? rttTotal/numPeers : 0); + buf.append(numPeers > 0 ? DataHelper.formatDuration2(rttTotal/numPeers) : '0'); buf.append("  "); - buf.append(numPeers > 0 ? rtoTotal/numPeers : 0); + buf.append(numPeers > 0 ? DataHelper.formatDuration2(rtoTotal/numPeers) : '0'); buf.append("  "); buf.append(sendTotal).append(" ").append(recvTotal).append("\n" + "").append(resentTotal); @@ -2139,6 +2138,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority buf.setLength(0); } + /** + * @return e.g. 3 sec or -3 sec + * formatDuration2() always prints negative numbers in ms + * @since 0.8.2 + */ + private static String formatDuration3(long x) { + if (x >= 0) + return DataHelper.formatDuration2(x); + return "-" + DataHelper.formatDuration2(0 - x); + } + private static final DecimalFormat _fmt = new DecimalFormat("#,##0.00"); private static final String formatKBps(int bps) { synchronized (_fmt) { From 8a385ffc32f995144ace92c237773a591e3a8d2f Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 17 Nov 2010 22:19:13 +0000 Subject: [PATCH 03/19] recognize postman b32 --- .../java/src/org/klomp/snark/web/I2PSnarkServlet.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index e1fb7837f9..18a262d22b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -174,6 +174,8 @@ public class I2PSnarkServlet extends Default { "\n" + ""); out.write(_("I2PSnark - Anonymous BitTorrent Client")); + if ("2".equals(peerParam)) + out.write(" | Debug Mode"); out.write("\n"); // we want it to go to the base URI so we don't refresh with some funky action= value @@ -780,7 +782,7 @@ public class I2PSnarkServlet extends Default { // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash String announce = snark.meta.getAnnounce(); if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") || - announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/")) { + announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") || announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/")) { Map trackers = _manager.getTrackers(); for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); From 138be42aa509198defab2712103cda66649662de Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 17 Nov 2010 22:26:31 +0000 Subject: [PATCH 04/19] bye .jsp part 2 --- .../net/i2p/router/web/ConfigNavHelper.java | 2 +- .../net/i2p/router/web/ConfigPeerHandler.java | 2 +- .../net/i2p/router/web/ConfigUIHandler.java | 2 +- .../src/net/i2p/router/web/GraphHelper.java | 4 +- .../i2p/router/web/LocaleWebAppHandler.java | 19 +++++++++- .../src/net/i2p/router/web/NetDbRenderer.java | 12 +++--- .../router/web/ProfileOrganizerRenderer.java | 4 +- .../net/i2p/router/web/ShitlistRenderer.java | 2 +- .../net/i2p/router/web/StatsGenerator.java | 4 +- .../i2p/router/web/SummaryBarRenderer.java | 38 +++++++++---------- .../src/net/i2p/router/web/SummaryHelper.java | 2 +- .../net/i2p/router/web/TunnelRenderer.java | 4 +- apps/routerconsole/jsp/index.html | 2 - installer/resources/clients.config | 2 +- 14 files changed, 56 insertions(+), 43 deletions(-) delete mode 100644 apps/routerconsole/jsp/index.html diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java index 40371a8333..44204f66d8 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java @@ -22,7 +22,7 @@ public class ConfigNavHelper extends HelperBase { public void renderNavBar(String requestURI) throws IOException { StringBuilder buf = new StringBuilder(1024); for (int i = 0; i < pages.length; i++) { - String page = "config" + pages[i] + ".jsp"; + String page = "config" + pages[i]; if (requestURI.indexOf(page) != -1) { // we are there buf.append(_(titles[i])); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java index 693febddcb..a0a3df8c9d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java @@ -20,7 +20,7 @@ public class ConfigPeerHandler extends FormHandler { } else if (_action.equals(_("Ban peer until restart"))) { Hash h = getHash(); if (h != null) { - _context.shitlist().shitlistRouterForever(h, _("Manually banned via {0}"), "configpeer.jsp"); + _context.shitlist().shitlistRouterForever(h, _("Manually banned via {0}"), "configpeer"); addFormNotice(_("Peer") + " " + _peer + " " + _("banned until restart") ); return; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java index 8f359e25cd..8c0925e4bc 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java @@ -29,7 +29,7 @@ public class ConfigUIHandler extends FormHandler { if (_context.router().saveConfig()) { if (!oldTheme.equals(_config)) addFormNotice(_("Theme change saved.") + - " " + + " " + _("Refresh the page to view.") + ""); } else { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java index 8fc78e7900..4f3dc4fcc7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -127,8 +127,8 @@ public class GraphHelper extends HelperBase { public String getForm() { saveSettings(); try { - _out.write("

" + _("Configure Graph Display") + " [" + _("Select Stats") + "]

"); - _out.write("
"); + _out.write("

" + _("Configure Graph Display") + " [" + _("Select Stats") + "]

"); + _out.write(""); _out.write(_("Periods") + ":
\n"); _out.write(_("Plot averages") + ": "); _out.write(_("or")+ " " +_("plot events") + ":
\n"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java index a075fb62f2..91ede9e529 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java @@ -13,7 +13,9 @@ import org.mortbay.jetty.servlet.WebApplicationHandler; /** * Convert foo.jsp to foo_xx.jsp for language xx. * This is appropriate for jsps with large amounts of text. - * This does not work for included jsps (e.g. summary*) + * + * Also, as of 0.8.2, rewrite "/" and "/index.html" to "/index.jsp",x + * and "/foo" to "/foo.jsp". * * @author zzz */ @@ -46,9 +48,22 @@ public class LocaleWebAppHandler extends WebApplicationHandler return; } + // transparent rewriting + if (pathInContext.equals("/") || pathInContext.equals("/index.html")) { + // home page + pathInContext = "/index.jsp"; + } else if (pathInContext.indexOf("/", 1) < 0 && + !pathInContext.endsWith(".jsp")) { + // add .jsp to pages at top level + pathInContext += ".jsp"; + } + //System.err.println("Path: " + pathInContext); String newPath = pathInContext; - if (pathInContext.endsWith(".jsp")) { + //if (pathInContext.endsWith(".jsp")) { + // We only ended up doing this for help.jsp, so save some effort + // unless we translate more pages like this + if (pathInContext.equals("/help.jsp")) { int len = pathInContext.length(); // ...but leave foo_xx.jsp alone if (len < 8 || pathInContext.charAt(len - 7) != '_') { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java index d2b0a17e90..131cacb926 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -105,7 +105,7 @@ public class NetDbRenderer { public void renderLeaseSetHTML(Writer out, boolean debug) throws IOException { StringBuilder buf = new StringBuilder(4*1024); buf.append("

" + _("Network Database Contents") + "

\n"); - buf.append("" + _("View RouterInfo") + ""); + buf.append("" + _("View RouterInfo") + ""); buf.append("

").append(_("LeaseSets")).append("

\n"); Hash ourRKey; Set leases; @@ -130,7 +130,7 @@ public class NetDbRenderer { Hash key = dest.calculateHash(); buf.append("").append(_("LeaseSet")).append(": ").append(key.toBase64()); if (_context.clientManager().isLocal(dest)) { - buf.append(" (" + _("Local") + " "); + buf.append(" (" + _("Local") + " "); if (! _context.clientManager().shouldPublishLeaseSet(key)) buf.append(_("Unpublished") + ' '); buf.append(_("Destination") + ' '); @@ -212,7 +212,7 @@ public class NetDbRenderer { * @param mode 0: our info and charts only; 1: full routerinfos and charts; 2: abbreviated routerinfos and charts */ public void renderStatusHTML(Writer out, int mode) throws IOException { - out.write("

" + _("Network Database Contents") + " (" + _("View LeaseSets") + ")

\n"); + out.write("

" + _("Network Database Contents") + " (" + _("View LeaseSets") + ")

\n"); if (!_context.netDb().isInitialized()) { out.write(_("Not initialized")); out.flush(); @@ -223,7 +223,7 @@ public class NetDbRenderer { boolean shortStats = mode == 2; boolean showStats = full || shortStats; Hash us = _context.routerHash(); - out.write("

" + _("Routers") + " (

" + _("Routers") + " (" + _("Show all routers")); else @@ -343,9 +343,9 @@ public class NetDbRenderer { } else { buf.append("" + _("Peer info for") + ": ").append(hash).append("\n"); if (full) { - buf.append("[Back]\n"); + buf.append("[Back]\n"); } else { - buf.append("[").append(_("Full entry")).append("]\n"); + buf.append("[").append(_("Full entry")).append("]\n"); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java index 7265578730..f452df2ba8 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java @@ -74,7 +74,7 @@ class ProfileOrganizerRenderer { if (older > 0) buf.append(_("Hiding {0} older profiles.", older)).append('\n'); if (standard > 0) - buf.append("").append(_("Hiding {0} standard profiles.", standard)).append("\n"); + buf.append("").append(_("Hiding {0} standard profiles.", standard)).append("\n"); buf.append("

"); buf.append(""); buf.append(""); @@ -173,7 +173,7 @@ class ProfileOrganizerRenderer { buf.append(" "); buf.append("\n"); + buf.append(" +-\n"); buf.append(""); // let's not build the whole page in memory (~500 bytes per peer) out.write(buf.toString()); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java index f0b9c910bb..12c6678728 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java @@ -67,7 +67,7 @@ public class ShitlistRenderer { else buf.append(_(entry.cause)); } - buf.append(" (").append(_("unban now")).append(")"); buf.append("\n"); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java index b229e84839..b1e1de9761 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java @@ -30,7 +30,7 @@ public class StatsGenerator { public void generateStatsPage(Writer out, boolean showAll) throws IOException { StringBuilder buf = new StringBuilder(16*1024); - buf.append("
"); + buf.append("
"); buf.append("
").append(_("profile")).append(""); - buf.append(" +-
\n" + - "

") .append(_("I2P Internals")) @@ -95,31 +95,31 @@ public class SummaryBarRenderer { "\n" + @@ -194,7 +194,7 @@ public class SummaryBarRenderer { .append(_helper.getUptime()) .append("
\n" + - "") .append(_("Tunnels")) .append("\n" + - "") .append(_("Peers")) .append("\n" + - "") .append(_("Profiles")) .append("\n" + - "") .append(_("NetDB")) .append("\n" + - "") .append(_("Logs")) @@ -131,13 +131,13 @@ public class SummaryBarRenderer { // .append(_("Jobs")) // .append("\n" + - "") .append(_("Graphs")) .append("\n" + - "") .append(_("Stats")) @@ -156,7 +156,7 @@ public class SummaryBarRenderer { - buf.append("

") .append(_("General")) @@ -173,7 +173,7 @@ public class SummaryBarRenderer { .append(_helper.getIdent()) .append(", ") .append(_("never reveal it to anyone")) - .append("\" href=\"/netdb.jsp?r=.\" target=\"_top\">") + .append("\" href=\"/netdb?r=.\" target=\"_top\">") .append(_("show")) .append("

\n" + - "

") .append(_("Network")) @@ -250,7 +250,7 @@ public class SummaryBarRenderer { buf.append("

") .append(ConfigRestartBean.renderStatus(_helper.getRequestURI(), _helper.getAction(), _helper.getConsoleNonce())) - .append("



") .append(_("Peers")) @@ -299,7 +299,7 @@ public class SummaryBarRenderer { boolean anotherLine = false; if (_helper.showFirewallWarning()) { - buf.append("

") .append(_("Check NAT/firewall")) @@ -338,7 +338,7 @@ public class SummaryBarRenderer { buf.append("
"); - buf.append("

") .append(_("Bandwidth in/out")) @@ -375,7 +375,7 @@ public class SummaryBarRenderer { .append(_helper.getOutboundTransferred()) .append("\n" + - "

") .append(_("Tunnels")) @@ -406,7 +406,7 @@ public class SummaryBarRenderer { .append(_helper.getShareRatio()) .append("\n" + - "


") .append(_("Congestion")) 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 5f2cb891b7..fe41f7f278 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -377,7 +377,7 @@ public class SummaryHelper extends HelperBase { buf.append("server.png\" alt=\"Server\" title=\"" + _("Server") + "\">"); else buf.append("client.png\" alt=\"Client\" title=\"" + _("Client") + "\">"); - buf.append(""); if (name.length() < 16) buf.append(name); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java index 3d52c653fa..bed2647d28 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java @@ -38,7 +38,7 @@ public class TunnelRenderer { } public void renderStatusHTML(Writer out) throws IOException { - out.write("

" + _("Exploratory tunnels") + " (" + _("configure") + ")

\n"); + out.write("

" + _("Exploratory tunnels") + " (" + _("configure") + ")

\n"); renderPool(out, _context.tunnelManager().getInboundExploratoryPool(), _context.tunnelManager().getOutboundExploratoryPool()); List destinations = null; @@ -60,7 +60,7 @@ public class TunnelRenderer { out.write("

" + _("Client tunnels for") + ' ' + _(name)); if (_context.clientManager().isLocal(client)) - out.write(" (" + _("configure") + ")

\n"); + out.write(" (" + _("configure") + ")

\n"); else out.write(" (" + _("dead") + ")

\n"); renderPool(out, in, outPool); diff --git a/apps/routerconsole/jsp/index.html b/apps/routerconsole/jsp/index.html deleted file mode 100644 index ea1321105e..0000000000 --- a/apps/routerconsole/jsp/index.html +++ /dev/null @@ -1,2 +0,0 @@ -I2P Router Console -Enter diff --git a/installer/resources/clients.config b/installer/resources/clients.config index db6fa628ee..f82aec5268 100644 --- a/installer/resources/clients.config +++ b/installer/resources/clients.config @@ -34,7 +34,7 @@ clientApp.3.startOnLoad=true # load a browser pointing at the web console whenever we start up clientApp.4.main=net.i2p.apps.systray.UrlLauncher clientApp.4.name=Open Router Console in web browser at startup -clientApp.4.args=http://127.0.0.1:7657/index.jsp +clientApp.4.args=http://127.0.0.1:7657/ clientApp.4.delay=3 clientApp.4.startOnLoad=true From 81d885c5a4bae951e5f51673139edd8f122673f5 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 18 Nov 2010 15:02:29 +0000 Subject: [PATCH 05/19] postman b32 take 2; recognize oga and ogv --- .../java/src/org/klomp/snark/web/I2PSnarkServlet.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 18a262d22b..4ebdbac26d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -789,7 +789,8 @@ public class I2PSnarkServlet extends Default { String name = (String)entry.getKey(); String baseURL = (String)entry.getValue(); if (!(baseURL.startsWith(announce) || // vvv hack for non-b64 announce in list vvv - (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")))) + (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")) || + (announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/") && baseURL.startsWith("http://tracker2.postman.i2p/")))) continue; int e = baseURL.indexOf('='); if (e < 0) @@ -1554,11 +1555,11 @@ public class I2PSnarkServlet extends Default { icon = "photo"; else if (mime.startsWith("audio/") || mime.equals("application/ogg") || plc.endsWith(".flac") || plc.endsWith(".m4a") || plc.endsWith(".wma") || - plc.endsWith(".ape")) + plc.endsWith(".ape") || plc.endsWith(".oga")) icon = "music"; else if (mime.startsWith("video/") || plc.endsWith(".mkv") || plc.endsWith(".m4v") || plc.endsWith(".mp4") || plc.endsWith(".wmv") || plc.endsWith(".flv") || - plc.endsWith(".ogm")) + plc.endsWith(".ogm") || plc.endsWith(".ogv")) icon = "film"; else if (mime.equals("application/zip") || mime.equals("application/x-gtar") || mime.equals("application/compress") || mime.equals("application/gzip") || From 1cad02c461d619dd23ec9a7cabb81542a1ab62bd Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 18 Nov 2010 19:27:37 +0000 Subject: [PATCH 06/19] remove jrandom signing key as it may no longer be secure --- core/java/src/net/i2p/crypto/TrustedUpdate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/src/net/i2p/crypto/TrustedUpdate.java b/core/java/src/net/i2p/crypto/TrustedUpdate.java index 7e8a2b1585..11f267712f 100644 --- a/core/java/src/net/i2p/crypto/TrustedUpdate.java +++ b/core/java/src/net/i2p/crypto/TrustedUpdate.java @@ -164,7 +164,7 @@ JXQAnA28vDmMMMH/WPbC5ixmJeGGNUiR addKey(propertyTrustedKeysTokens.nextToken().trim(), ""); } else { - addKey(DEFAULT_TRUSTED_KEY, "jrandom@mail.i2p"); + //addKey(DEFAULT_TRUSTED_KEY, "jrandom@mail.i2p"); addKey(DEFAULT_TRUSTED_KEY2, "zzz@mail.i2p"); //addKey(DEFAULT_TRUSTED_KEY3, "complication@mail.i2p"); addKey(DEFAULT_TRUSTED_KEY4, "HungryHobo@mail.i2p"); From 50d9080e26d7c64dc11c99e8a7ad9fd988cc276d Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 00:36:24 +0000 Subject: [PATCH 07/19] add note --- installer/resources/proxy/README.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 installer/resources/proxy/README.txt diff --git a/installer/resources/proxy/README.txt b/installer/resources/proxy/README.txt new file mode 100644 index 0000000000..dc0ca866c7 --- /dev/null +++ b/installer/resources/proxy/README.txt @@ -0,0 +1,7 @@ +Note to translators and editors: + +These are the error pages displayed in the HTTP proxy, +with the HTTP headers prepended. + +All files in this directory must be DOS formatted with \r\n line endings, +so the HTTP header lines are standards-compliant. Thank you. From e940f51599f7b363b6d2e8c331037b147e05dc17 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 00:40:33 +0000 Subject: [PATCH 08/19] * SecureFile: New class, catch places that were missed, add i2p.insecureFiles option to disable (default false) --- .../src/net/i2p/addressbook/ConfigParser.java | 3 +- .../src/org/klomp/snark/I2PSnarkUtil.java | 3 +- .../java/src/org/klomp/snark/Storage.java | 5 +- core/java/src/net/i2p/I2PAppContext.java | 18 +++++ .../src/net/i2p/util/SecureDirectory.java | 9 +-- core/java/src/net/i2p/util/SecureFile.java | 81 +++++++++++++++++++ .../net/i2p/util/SecureFileOutputStream.java | 16 +++- 7 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 core/java/src/net/i2p/util/SecureFile.java diff --git a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java index c963ecce54..44bbbe7813 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java @@ -35,6 +35,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import net.i2p.util.SecureFile; import net.i2p.util.SecureFileOutputStream; /** @@ -280,7 +281,7 @@ public class ConfigParser { * if file cannot be written to. */ public static void write(Map map, File file) throws IOException { - File tmp = File.createTempFile("hoststxt-", ".tmp", file.getAbsoluteFile().getParentFile()); + File tmp = SecureFile.createTempFile("hoststxt-", ".tmp", file.getAbsoluteFile().getParentFile()); ConfigParser .write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(tmp), "UTF-8"))); boolean success = tmp.renameTo(file); diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index 8edc92fdf3..001928d479 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -27,6 +27,7 @@ import net.i2p.util.EepGet; import net.i2p.util.FileUtil; import net.i2p.util.Log; import net.i2p.util.SecureDirectory; +import net.i2p.util.SecureFile; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; import net.i2p.util.Translate; @@ -244,7 +245,7 @@ public class I2PSnarkUtil { File out = null; try { // we could use the system tmp dir but deleteOnExit() doesn't seem to work on all platforms... - out = File.createTempFile("i2psnark", null, _tmpDir); + out = SecureFile.createTempFile("i2psnark", null, _tmpDir); } catch (IOException ioe) { ioe.printStackTrace(); if (out != null) diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index 3e2a4ad631..87aa0d3572 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.StringTokenizer; import net.i2p.crypto.SHA1; +import net.i2p.util.SecureFile; /** * Maintains pieces on disk. Can be used to store and retrieve pieces. @@ -462,7 +463,7 @@ public class Storage /** use a saved bitfield and timestamp from a config file */ public void check(String rootDir, long savedTime, BitField savedBitField) throws IOException { - File base = new File(rootDir, filterName(metainfo.getName())); + File base = new SecureFile(rootDir, filterName(metainfo.getName())); boolean useSavedBitField = savedTime > 0 && savedBitField != null; List files = metainfo.getFiles(); @@ -623,7 +624,7 @@ public class Storage else { // The final element (file) in the hierarchy. - f = new File(base, name); + f = new SecureFile(base, name); if (!f.createNewFile() && !f.exists()) throw new IOException("Could not create file " + f); } diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 98e7d6af9a..b497796408 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -114,6 +114,11 @@ public class I2PAppContext { * */ public static I2PAppContext getGlobalContext() { + // skip the global lock + I2PAppContext rv = _globalAppContext; + if (rv != null) + return rv; + synchronized (I2PAppContext.class) { if (_globalAppContext == null) { _globalAppContext = new I2PAppContext(false, null); @@ -122,6 +127,18 @@ public class I2PAppContext { return _globalAppContext; } + /** + * Pull the default context, WITHOUT creating a new one. + * Use this in static methods used early in router initialization, + * where creating a context messes things up. + * + * @return context or null + * @since 0.8.2 + */ + public static I2PAppContext getCurrentContext() { + return _globalAppContext; + } + /** * Lets root a brand new context * @@ -257,6 +274,7 @@ public class I2PAppContext { _appDir = _routerDir; } /****** + (new Exception("Initialized by")).printStackTrace(); System.err.println("Base directory: " + _baseDir.getAbsolutePath()); System.err.println("Config directory: " + _configDir.getAbsolutePath()); System.err.println("Router directory: " + _routerDir.getAbsolutePath()); diff --git a/core/java/src/net/i2p/util/SecureDirectory.java b/core/java/src/net/i2p/util/SecureDirectory.java index 30d609e96f..d238cc694d 100644 --- a/core/java/src/net/i2p/util/SecureDirectory.java +++ b/core/java/src/net/i2p/util/SecureDirectory.java @@ -5,15 +5,14 @@ import java.io.File; /** * Same as File but sets the file mode after mkdir() so it can * be read and written by the owner only (i.e. 700 on linux) + * As of 0.8.2, just use SecureFile instead of this. * * @since 0.8.1 * @author zzz */ public class SecureDirectory extends File { - private static final boolean canSetPerms = - (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0; - private static final boolean isNotWindows = !System.getProperty("os.name").startsWith("Win"); + protected static final boolean isNotWindows = !System.getProperty("os.name").startsWith("Win"); public SecureDirectory(String pathname) { super(pathname); @@ -54,8 +53,8 @@ public class SecureDirectory extends File { * Tries to set the permissions to 700, * ignores errors */ - private void setPerms() { - if (!canSetPerms) + protected void setPerms() { + if (!SecureFileOutputStream.canSetPerms()) return; try { setReadable(false, false); diff --git a/core/java/src/net/i2p/util/SecureFile.java b/core/java/src/net/i2p/util/SecureFile.java new file mode 100644 index 0000000000..a931abb556 --- /dev/null +++ b/core/java/src/net/i2p/util/SecureFile.java @@ -0,0 +1,81 @@ +package net.i2p.util; + +import java.io.File; +import java.io.IOException; + +/** + * Same as SecureDirectory but sets the file mode after createNewFile() + * and createTempFile() also. So just use this instead. + * Probably should have just made this class in the beginning and not had two. + * + * @since 0.8.2 + * @author zzz + */ +public class SecureFile extends SecureDirectory { + + public SecureFile(String pathname) { + super(pathname); + } + + public SecureFile(String parent, String child) { + super(parent, child); + } + + public SecureFile(File parent, String child) { + super(parent, child); + } + + /** + * Sets file to mode 600 if the file is created + */ + @Override + public boolean createNewFile() throws IOException { + boolean rv = super.createNewFile(); + if (rv) + setPerms(); + return rv; + } + + /** + * Sets file to mode 600 when the file is created + */ + public static File createTempFile(String prefix, String suffix) throws IOException { + File rv = File.createTempFile(prefix, suffix); + // same thing as below but static + SecureFileOutputStream.setPerms(rv); + return rv; + } + + /** + * Sets file to mode 600 when the file is created + */ + public static File createTempFile(String prefix, String suffix, File directory) throws IOException { + File rv = File.createTempFile(prefix, suffix, directory); + // same thing as below but static + SecureFileOutputStream.setPerms(rv); + return rv; + } + + /** + * Tries to set the permissions to 600, + * ignores errors + */ + @Override + protected void setPerms() { + if (!SecureFileOutputStream.canSetPerms()) + return; + try { + setReadable(false, false); + setReadable(true, true); + setWritable(false, false); + setWritable(true, true); + if (isNotWindows && isDirectory()) { + setExecutable(false, false); + setExecutable(true, true); + } + } catch (Throwable t) { + // NoSuchMethodException or NoSuchMethodError if we somehow got the + // version detection wrong or the JVM doesn't support it + } + } +} diff --git a/core/java/src/net/i2p/util/SecureFileOutputStream.java b/core/java/src/net/i2p/util/SecureFileOutputStream.java index 01c6eba718..9494827eb6 100644 --- a/core/java/src/net/i2p/util/SecureFileOutputStream.java +++ b/core/java/src/net/i2p/util/SecureFileOutputStream.java @@ -4,6 +4,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import net.i2p.I2PAppContext; + /** * Same as FileOutputStream but sets the file mode so it can only * be read and written by the owner only (i.e. 600 on linux) @@ -13,7 +15,7 @@ import java.io.FileOutputStream; */ public class SecureFileOutputStream extends FileOutputStream { - private static final boolean canSetPerms = + private static final boolean oneDotSix = (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0; /** @@ -51,12 +53,22 @@ public class SecureFileOutputStream extends FileOutputStream { setPerms(file); } + /** @since 0.8.2 */ + static boolean canSetPerms() { + if (!oneDotSix) + return false; + I2PAppContext ctx = I2PAppContext.getCurrentContext(); + if (ctx == null) + return true; + return !ctx.getBooleanProperty("i2p.insecureFiles"); + } + /** * Tries to set the permissions to 600, * ignores errors */ public static void setPerms(File f) { - if (!canSetPerms) + if (!canSetPerms()) return; try { f.setReadable(false, false); From 4545a98968248a5845053def7a3745fd0e8f8f9a Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 14:41:26 +0000 Subject: [PATCH 09/19] More work on error propagation and improving log messages in i2ptunnel and I2CP client --- .../java/src/net/i2p/i2ptunnel/I2PTunnel.java | 86 +++++++++++---- .../i2p/i2ptunnel/I2PTunnelClientBase.java | 103 +++++++++++++++--- .../i2p/i2ptunnel/I2PTunnelConnectClient.java | 4 +- .../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 6 +- .../net/i2p/i2ptunnel/I2PTunnelIRCClient.java | 4 +- .../net/i2p/i2ptunnel/I2PTunnelServer.java | 48 ++++++-- .../i2p/i2ptunnel/InternalSocketRunner.java | 2 +- .../net/i2p/i2ptunnel/TunnelController.java | 4 +- .../i2ptunnel/socks/I2PSOCKSIRCTunnel.java | 2 +- .../i2p/i2ptunnel/socks/I2PSOCKSTunnel.java | 4 +- .../src/net/i2p/i2ptunnel/web/IndexBean.java | 4 +- core/java/src/net/i2p/I2PException.java | 37 +++---- .../src/net/i2p/client/I2PSessionImpl.java | 8 +- .../src/net/i2p/client/I2PSimpleSession.java | 4 +- 14 files changed, 223 insertions(+), 93 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 17049626c0..ec38052cc0 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -85,8 +85,11 @@ public class I2PTunnel implements Logging, EventDispatcher { public boolean ownDest = false; + /** the I2CP port */ public String port = System.getProperty(I2PClient.PROP_TCP_PORT, "7654"); + /** the I2CP host */ public String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1"); + /** the listen-on host. Sadly the listen-on port does not have a field. */ public String listenHost = host; public long readTimeout = -1; @@ -689,8 +692,10 @@ public class I2PTunnel implements Logging, EventDispatcher { addtask(task); notifyEvent("clientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create a client [" + host + ":"+ port + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + port + "]"); + String msg = "Invalid I2PTunnel configuration to create an HTTP Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); notifyEvent("clientTaskId", Integer.valueOf(-1)); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down @@ -763,8 +768,10 @@ public class I2PTunnel implements Logging, EventDispatcher { addtask(task); notifyEvent("httpclientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create an httpclient [" + host + ":"+ clientPort + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + clientPort + "]"); + String msg = "Invalid I2PTunnel configuration to create an HTTP Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); notifyEvent("httpclientTaskId", Integer.valueOf(-1)); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down @@ -829,7 +836,10 @@ public class I2PTunnel implements Logging, EventDispatcher { task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, (EventDispatcher) this, this); addtask(task); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create a connect client [" + host + ":"+ _port + "]", iae); + String msg = "Invalid I2PTunnel configuration to create a CONNECT client connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down // This doesn't work for CLI though... and the tunnel doesn't close itself after error, @@ -892,8 +902,10 @@ public class I2PTunnel implements Logging, EventDispatcher { addtask(task); notifyEvent("ircclientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create an ircclient [" + host + ":"+ _port + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + _port + "]"); + String msg = "Invalid I2PTunnel configuration to create an IRC client connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); notifyEvent("ircclientTaskId", Integer.valueOf(-1)); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down @@ -939,10 +951,18 @@ public class I2PTunnel implements Logging, EventDispatcher { isShared = "true".equalsIgnoreCase(args[1].trim()); ownDest = !isShared; - I2PTunnelTask task; - task = new I2PSOCKSTunnel(_port, l, ownDest, (EventDispatcher) this, this, null); - addtask(task); - notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + try { + I2PTunnelTask task = new I2PSOCKSTunnel(_port, l, ownDest, (EventDispatcher) this, this, null); + addtask(task); + notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + } catch (IllegalArgumentException iae) { + String msg = "Invalid I2PTunnel configuration to create a SOCKS Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); + notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); + throw iae; + } } else { l.log("sockstunnel "); l.log(" creates a tunnel that distributes SOCKS requests."); @@ -978,10 +998,18 @@ public class I2PTunnel implements Logging, EventDispatcher { String privateKeyFile = null; if (args.length == 3) privateKeyFile = args[2]; - I2PTunnelTask task; - task = new I2PSOCKSIRCTunnel(_port, l, ownDest, (EventDispatcher) this, this, privateKeyFile); - addtask(task); - notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + try { + I2PTunnelTask task = new I2PSOCKSIRCTunnel(_port, l, ownDest, (EventDispatcher) this, this, privateKeyFile); + addtask(task); + notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + } catch (IllegalArgumentException iae) { + String msg = "Invalid I2PTunnel configuration to create a SOCKS IRC Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); + notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); + throw iae; + } } else { l.log("socksirctunnel [ []]"); l.log(" creates a tunnel for SOCKS IRC."); @@ -1019,10 +1047,19 @@ public class I2PTunnel implements Logging, EventDispatcher { if (_port <= 0) throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); - StreamrConsumer task = new StreamrConsumer(_host, _port, args[2], l, (EventDispatcher) this, this); - task.startRunning(); - addtask(task); - notifyEvent("streamrtunnelTaskId", Integer.valueOf(task.getId())); + try { + StreamrConsumer task = new StreamrConsumer(_host, _port, args[2], l, (EventDispatcher) this, this); + task.startRunning(); + addtask(task); + notifyEvent("streamrtunnelTaskId", Integer.valueOf(task.getId())); + } catch (IllegalArgumentException iae) { + String msg = "Invalid I2PTunnel configuration to create a Streamr Client connecting to the router at " + host + ':'+ port + + " and sending to " + _host + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); + notifyEvent("streamrtunnnelTaskId", Integer.valueOf(-1)); + throw iae; + } } else { l.log("streamrclient "); l.log(" creates a tunnel that receives streaming data."); @@ -1409,7 +1446,8 @@ public class I2PTunnel implements Logging, EventDispatcher { for (Iterator it = tasks.iterator(); it.hasNext();) { I2PTunnelTask t = (I2PTunnelTask) it.next(); int id = t.getId(); - _log.debug(getPrefix() + "closetask(): parsing task " + id + " (" + t.toString() + ")"); + if (_log.shouldLog(Log.DEBUG)) + _log.debug(getPrefix() + "closetask(): parsing task " + id + " (" + t.toString() + ")"); if (id == num) { closed = closetask(t, forced, l); break; @@ -1427,9 +1465,13 @@ public class I2PTunnel implements Logging, EventDispatcher { * */ private boolean closetask(I2PTunnelTask t, boolean forced, Logging l) { - l.log("Closing task " + t.getId() + (forced ? " forced..." : "...")); + if (_log.shouldLog(Log.INFO)) + _log.info("Closing task " + t.getId() + (forced ? " forced..." : "...")); + //l.log("Closing task " + t.getId() + (forced ? " forced..." : "...")); if (t.close(forced)) { - l.log("Task " + t.getId() + " closed."); + if (_log.shouldLog(Log.INFO)) + _log.info("Task " + t.getId() + " closed."); + //l.log("Task " + t.getId() + " closed."); return true; } return false; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index 71a1561eaa..54d31d29e4 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -128,10 +128,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna configurePool(tunnel); if (open && listenerReady) { - l.log("Ready! Port " + getLocalPort()); + l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort); notifyEvent("openBaseClientResult", "ok"); } else { - l.log("Error listening - please see the logs!"); + l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs"); notifyEvent("openBaseClientResult", "error"); } } @@ -181,7 +181,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna while (sockMgr == null) { verifySocketManager(); if (sockMgr == null) { - _log.log(Log.CRIT, "Unable to create socket manager (our own? " + ownDest + ")"); + _log.error("Unable to connect to router and build tunnels for " + handlerName); + // FIXME there is a loop in buildSocketManager(), do we really need another one here? + // no matter, buildSocketManager() now throws an IllegalArgumentException try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} } } @@ -212,12 +214,12 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna if (open && listenerReady) { if (openNow) - l.log("Ready! Port " + getLocalPort()); + l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort); else - l.log("Listening on port " + getLocalPort() + ", delaying tunnel open until required"); + l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort + ", delaying tunnel open until required"); notifyEvent("openBaseClientResult", "ok"); } else { - l.log("Error listening - please see the logs!"); + l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs"); notifyEvent("openBaseClientResult", "error"); } } @@ -257,6 +259,8 @@ 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 + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager */ protected void verifySocketManager() { synchronized(sockLock) { @@ -289,15 +293,33 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna /** this is ONLY for shared clients */ private static I2PSocketManager socketManager; - /** this is ONLY for shared clients */ + + /** + * this is ONLY for shared clients + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected synchronized I2PSocketManager getSocketManager() { return getSocketManager(getTunnel(), this.privKeyFile); } - /** this is ONLY for shared clients */ + + /** + * this is ONLY for shared clients + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) { return getSocketManager(tunnel, null); } - /** this is ONLY for shared clients */ + + /** + * this is ONLY for shared clients + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) { if (socketManager != null) { I2PSession s = socketManager.getSession(); @@ -319,15 +341,43 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna return socketManager; } + /** + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected I2PSocketManager buildSocketManager() { - return buildSocketManager(getTunnel(), this.privKeyFile); + return buildSocketManager(getTunnel(), this.privKeyFile, this.l); } + /** + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel) { return buildSocketManager(tunnel, null); } - /** @param pkf absolute path or null */ + private static final int RETRY_DELAY = 20*1000; + private static final int MAX_RETRIES = 4; + + /** + * @param pkf absolute path or null + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf) { + return buildSocketManager(tunnel, pkf, null); + } + + /** + * @param pkf absolute path or null + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ + protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf, Logging log) { Properties props = new Properties(); props.putAll(tunnel.getClientOptions()); int portNum = 7654; @@ -340,6 +390,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } I2PSocketManager sockManager = null; + // Todo: Can't stop a tunnel from the UI while it's in this loop (no session yet) + int retries = 0; while (sockManager == null) { if (pkf != null) { // Persistent client dest @@ -348,8 +400,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna fis = new FileInputStream(pkf); sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props); } catch (IOException ioe) { + if (log != null) + log.log("Error opening key file " + ioe); _log.error("Error opening key file", ioe); - // this is going to loop but if we break we'll get a NPE + throw new IllegalArgumentException("Error opening key file " + ioe); } finally { if (fis != null) try { fis.close(); } catch (IOException ioe) {} @@ -359,8 +413,22 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } if (sockManager == null) { - _log.log(Log.CRIT, "Unable to create socket manager"); - try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} + // try to make this error sensible as it will happen... sadly we can't get to the listenPort, only the listenHost + String msg = "Unable to connect to the router at " + tunnel.host + ':' + portNum + + " and build tunnels for the client"; + if (++retries < MAX_RETRIES) { + if (log != null) + log.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + _log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + } else { + if (log != null) + log.log(msg + ", giving up"); + _log.log(Log.CRIT, msg + ", giving up"); + // not clear if callers can handle null + //return null; + throw new IllegalArgumentException(msg); + } + try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {} } } sockManager.setName("Client"); @@ -479,7 +547,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna localPort = ss.getLocalPort(); } notifyEvent("clientLocalPort", new Integer(ss.getLocalPort())); - l.log("Listening for clients on port " + localPort + " of " + getTunnel().listenHost); + // duplicates message in constructor + //l.log("Listening for clients on port " + localPort + " of " + getTunnel().listenHost); // Notify constructor that port is ready synchronized (this) { @@ -608,7 +677,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } } // else the app chaining to this one closes it! } - l.log("Closing client " + toString()); + l.log("Stopping client " + toString()); open = false; try { if (ss != null) ss.close(); @@ -616,7 +685,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna ex.printStackTrace(); return false; } - l.log("Client closed."); + //l.log("Client closed."); } synchronized (_waitingSockets) { _waitingSockets.notifyAll(); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 16f8447eca..574f723feb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -115,7 +115,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R public I2PTunnelConnectClient(int localPort, Logging l, boolean ownDest, String wwwProxy, EventDispatcher notifyThis, I2PTunnel tunnel) throws IllegalArgumentException { - super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel); + super(localPort, ownDest, l, notifyThis, "HTTPS Proxy on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openConnectClientResult", "error"); @@ -128,7 +128,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R _proxyList.add(tok.nextToken().trim()); } - setName(getLocalPort() + " -> ConnectClient [Outproxy list: " + wwwProxy + "]"); + setName("HTTPS Proxy on " + tunnel.listenHost + ':' + localPort); startRunning(); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 14289cf2fc..1301fcd2cb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -166,7 +166,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn super(localPort, l, sockMgr, tunnel, notifyThis, clientId); // proxyList = new ArrayList(); - setName(getLocalPort() + " -> HTTPClient [NO PROXIES]"); + setName("HTTP Proxy on " + getTunnel().listenHost + ':' + localPort); startRunning(); notifyEvent("openHTTPClientResult", "ok"); @@ -178,7 +178,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn public I2PTunnelHTTPClient(int localPort, Logging l, boolean ownDest, String wwwProxy, EventDispatcher notifyThis, I2PTunnel tunnel) throws IllegalArgumentException { - super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel); + super(localPort, ownDest, l, notifyThis, "HTTP Proxy on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel); //proxyList = new ArrayList(); // We won't use outside of i2p if (waitEventValue("openBaseClientResult").equals("error")) { @@ -192,7 +192,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn _proxyList.add(tok.nextToken().trim()); } - setName(getLocalPort() + " -> HTTPClient [WWW outproxy list: " + wwwProxy + "]"); + setName("HTTP Proxy on " + tunnel.listenHost + ':' + localPort); startRunning(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index d0dc227ec1..6938a11ef5 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -46,7 +46,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable ownDest, l, notifyThis, - "IRCHandler " + (++__clientId), tunnel, pkf); + "IRC Client on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel, pkf); StringTokenizer tok = new StringTokenizer(destinations, ", "); dests = new ArrayList(2); @@ -80,7 +80,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable //return; } - setName(getLocalPort() + " -> IRCClient"); + setName("IRC Client on " + tunnel.listenHost + ':' + localPort); startRunning(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java index 96265ff161..fc39e19964 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java @@ -61,16 +61,24 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { private int DEFAULT_LOCALPORT = 4488; protected int localPort = DEFAULT_LOCALPORT; + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { - super(host + ":" + port + " <- " + privData, notifyThis, tunnel); + super("Server at " + host + ':' + port, notifyThis, tunnel); ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData)); SetUsePool(tunnel); init(host, port, bais, privData, l); } + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ public I2PTunnelServer(InetAddress host, int port, File privkey, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { - super(host + ":" + port + " <- " + privkeyname, notifyThis, tunnel); + super("Server at " + host + ':' + port, notifyThis, tunnel); SetUsePool(tunnel); FileInputStream fis = null; try { @@ -85,8 +93,12 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } } + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { - super(host + ":" + port + " <- " + privkeyname, notifyThis, tunnel); + super("Server at " + host + ':' + port, notifyThis, tunnel); SetUsePool(tunnel); init(host, port, privData, privkeyname, l); } @@ -100,6 +112,13 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { _usePool = DEFAULT_USE_POOL; } + private static final int RETRY_DELAY = 20*1000; + private static final int MAX_RETRIES = 4; + + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ private void init(InetAddress host, int port, InputStream privData, String privkeyname, Logging l) { this.l = l; this.remoteHost = host; @@ -111,7 +130,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { try { portNum = Integer.parseInt(getTunnel().port); } catch (NumberFormatException nfe) { - _log.log(Log.CRIT, "Invalid port specified [" + getTunnel().port + "], reverting to " + portNum); + _log.error("Invalid port specified [" + getTunnel().port + "], reverting to " + portNum); } } @@ -125,6 +144,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } // Todo: Can't stop a tunnel from the UI while it's in this loop (no session yet) + int retries = 0; while (sockMgr == null) { synchronized (slock) { sockMgr = I2PSocketManagerFactory.createManager(privDataCopy, getTunnel().host, portNum, @@ -132,15 +152,25 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } if (sockMgr == null) { - _log.log(Log.CRIT, "Unable to create socket manager"); - try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} + // try to make this error sensible as it will happen... + String msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum + + " and build tunnels for the server at " + getTunnel().listenHost + ':' + port; + if (++retries < MAX_RETRIES) { + this.l.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + _log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + } else { + this.l.log(msg + ", giving up"); + _log.log(Log.CRIT, msg + ", giving up"); + throw new IllegalArgumentException(msg); + } + try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {} privDataCopy.reset(); } } sockMgr.setName("Server"); getTunnel().addSession(sockMgr.getSession()); - l.log("Ready!"); + l.log("Tunnels ready for server at " + getTunnel().listenHost + ':' + port); notifyEvent("openServerResult", "ok"); open = true; } @@ -206,7 +236,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } return false; } - l.log("Shutting down server " + toString()); + l.log("Stopping tunnels for server at " + getTunnel().listenHost + ':' + this.remotePort); try { if (i2pss != null) i2pss.close(); getTunnel().removeSession(sockMgr.getSession()); @@ -215,7 +245,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { _log.error("Error destroying the session", ex); //System.exit(1); } - l.log("Server shut down."); + //l.log("Server shut down."); open = false; return true; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java index d6f4dcc394..edb1434fe2 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java @@ -39,7 +39,7 @@ class InternalSocketRunner implements Runnable { } } catch (IOException ex) { if (this.open) { - _log.error("Error listening for internal connections on " + this.port, ex); + _log.error("Error listening for internal connections on port " + this.port, ex); } this.open = false; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 7a9b1dbd67..4299b6d478 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -128,8 +128,8 @@ public class TunnelController implements Logging { try { doStartTunnel(); } catch (Exception e) { - _log.error("Error starting up the tunnel", e); - log("Error starting up the tunnel - " + e.getMessage()); + _log.error("Error starting the tunnel " + getName(), e); + log("Error starting the tunnel " + getName() + ": " + e.getMessage()); // if we don't acquire() then the release() in stopTunnel() won't work acquire(); stopTunnel(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java index f1bc4874c2..01888d8d10 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java @@ -36,7 +36,7 @@ public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel { /** @param pkf private key file name or null for transient key */ public I2PSOCKSIRCTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) { super(localPort, l, ownDest, notifyThis, tunnel, pkf); - setName(getLocalPort() + " -> SOCKSIRCTunnel"); + setName("SOCKS IRC Proxy on " + tunnel.listenHost + ':' + localPort); } /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java index 740aa4549b..14cafbdfdc 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java @@ -36,14 +36,14 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase { /** @param pkf private key file name or null for transient key */ public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) { - super(localPort, ownDest, l, notifyThis, "SOCKSHandler", tunnel, pkf); + super(localPort, ownDest, l, notifyThis, "SOCKS Proxy on " + tunnel.listenHost + ':' + localPort, tunnel, pkf); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openSOCKSTunnelResult", "error"); return; } - setName(getLocalPort() + " -> SOCKSTunnel"); + setName("SOCKS Proxy on " + tunnel.listenHost + ':' + localPort); parseOptions(); startRunning(); 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 c21b45ee9d..7ca9243260 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -226,7 +226,7 @@ public class IndexBean { // give the messages a chance to make it to the window try { Thread.sleep(1000); } catch (InterruptedException ie) {} // and give them something to look at in any case - return _("Starting tunnel..."); + return _("Starting tunnel") + ' ' + getTunnelName(_tunnel) + " &hellip"; } private String stop() { @@ -239,7 +239,7 @@ public class IndexBean { // give the messages a chance to make it to the window try { Thread.sleep(1000); } catch (InterruptedException ie) {} // and give them something to look at in any case - return _("Stopping tunnel..."); + return _("Stopping tunnel") + ' ' + getTunnelName(_tunnel) + " &hellip"; } private String saveChanges() { diff --git a/core/java/src/net/i2p/I2PException.java b/core/java/src/net/i2p/I2PException.java index d263766ef3..70b7fdbfca 100644 --- a/core/java/src/net/i2p/I2PException.java +++ b/core/java/src/net/i2p/I2PException.java @@ -15,39 +15,28 @@ import java.io.PrintWriter; /** * Base class of I2P exceptions * + * This was originally used to provide chained exceptions, but + * those were added to Exception in Java 1.4, so this class provides nothing + * extra at the moment. + * * @author jrandom */ public class I2PException extends Exception { - private Throwable _source; public I2PException() { - this(null, null); + super(); } public I2PException(String msg) { - this(msg, null); - } - - public I2PException(String msg, Throwable source) { super(msg); - _source = source; - } - - @Override - public void printStackTrace() { - if (_source != null) _source.printStackTrace(); - super.printStackTrace(); - } - - @Override - public void printStackTrace(PrintStream ps) { - if (_source != null) _source.printStackTrace(ps); - super.printStackTrace(ps); } - @Override - public void printStackTrace(PrintWriter pw) { - if (_source != null) _source.printStackTrace(pw); - super.printStackTrace(pw); + public I2PException(String msg, Throwable cause) { + super(msg, cause); } -} \ No newline at end of file + + /** @since 0.8.2 */ + public I2PException(Throwable cause) { + super(cause); + } +} diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index cd60b60cc0..783222bc95 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -304,7 +304,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa while (!_dateReceived) { if (waitcount++ > 30) { closeSocket(); - throw new IOException("no date handshake"); + throw new IOException("No handshake received from the router"); } try { synchronized (_dateReceivedLock) { @@ -327,7 +327,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa _producer.disconnect(this); } catch (I2PSessionException ipe) {} closeSocket(); - throw new IOException("no leaseset"); + throw new IOException("No tunnels built after waiting 5 minutes... are there network problems?"); } synchronized (_leaseSetWait) { try { @@ -346,11 +346,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa } catch (UnknownHostException uhe) { _closed = true; setOpening(false); - throw new I2PSessionException(getPrefix() + "Invalid session configuration", uhe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe); } catch (IOException ioe) { _closed = true; setOpening(false); - throw new I2PSessionException(getPrefix() + "Problem connecting to " + _hostname + " on port " + _portNum, ioe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe); } } diff --git a/core/java/src/net/i2p/client/I2PSimpleSession.java b/core/java/src/net/i2p/client/I2PSimpleSession.java index af5ab9a75b..f4bc3e812c 100644 --- a/core/java/src/net/i2p/client/I2PSimpleSession.java +++ b/core/java/src/net/i2p/client/I2PSimpleSession.java @@ -86,10 +86,10 @@ class I2PSimpleSession extends I2PSessionImpl2 { } catch (UnknownHostException uhe) { _closed = true; - throw new I2PSessionException(getPrefix() + "Bad host ", uhe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe); } catch (IOException ioe) { _closed = true; - throw new I2PSessionException(getPrefix() + "Problem connecting to " + _hostname + " on port " + _portNum, ioe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe); } } From f0ac96cab143949689e5bb254c5f64b0e5fcadb0 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 14:42:10 +0000 Subject: [PATCH 10/19] Increase i2ptunnel nonce queue size again --- apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7ca9243260..0640c2a310 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -90,7 +90,7 @@ public class IndexBean { //static final String PROP_NONCE = IndexBean.class.getName() + ".nonce"; //static final String PROP_NONCE_OLD = PROP_NONCE + '2'; /** 3 wasn't enough for some browsers. They are reloading the page for some reason - maybe HEAD? @since 0.8.1 */ - private static final int MAX_NONCES = 5; + private static final int MAX_NONCES = 8; /** store nonces in a static FIFO instead of in System Properties @since 0.8.1 */ private static final List _nonces = new ArrayList(MAX_NONCES + 1); From 166f378f2f1ee325853b22c76efd9a2215b561ad Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 15:23:25 +0000 Subject: [PATCH 11/19] clean up more urls and POST self-references --- .../java/src/net/i2p/router/web/StatsGenerator.java | 2 +- apps/routerconsole/jsp/config.jsp | 6 +++--- apps/routerconsole/jsp/configadvanced.jsp | 2 +- apps/routerconsole/jsp/configclients.jsp | 2 +- apps/routerconsole/jsp/configkeyring.jsp | 2 +- apps/routerconsole/jsp/configlogging.jsp | 2 +- apps/routerconsole/jsp/configpeer.jsp | 4 ++-- apps/routerconsole/jsp/configservice.jsp | 6 +++--- apps/routerconsole/jsp/configstats.jsp | 2 +- apps/routerconsole/jsp/configtunnels.jsp | 2 +- apps/routerconsole/jsp/configui.jsp | 2 +- apps/routerconsole/jsp/configupdate.jsp | 2 +- 12 files changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java index b1e1de9761..6b6a8b6163 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java @@ -30,7 +30,7 @@ public class StatsGenerator { public void generateStatsPage(Writer out, boolean showAll) throws IOException { StringBuilder buf = new StringBuilder(16*1024); - buf.append("
"); + buf.append("
"); buf.append(" > - <%=intl._("Enable UPnP to open firewall ports")%> - <%=intl._("UPnP status")%> + <%=intl._("Enable UPnP to open firewall ports")%> - <%=intl._("UPnP status")%>

<%=intl._("IP Configuration")%>:
<%=intl._("Externally reachable hostname or IP address")%>:
> @@ -196,7 +196,7 @@

  • <%=intl._("Multiple firewall/routers in the internet connection path")%>
  • <%=intl._("UPnP device change, reset, or address change")%>

    -<%=intl._("Review the UPnP status here.")%> +<%=intl._("Review the UPnP status here.")%> <%=intl._("UPnP may be enabled or disabled above, but a change requires a router restart to take effect.")%>

    <%=intl._("Hostnames entered above will be published in the network database.")%> <%=intl._("They are not private.")%> diff --git a/apps/routerconsole/jsp/configadvanced.jsp b/apps/routerconsole/jsp/configadvanced.jsp index 727bb08467..566d0c1bad 100644 --- a/apps/routerconsole/jsp/configadvanced.jsp +++ b/apps/routerconsole/jsp/configadvanced.jsp @@ -23,7 +23,7 @@

    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigAdvancedHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigAdvancedHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigAdvancedHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configclients.jsp b/apps/routerconsole/jsp/configclients.jsp index c9a668c797..49430e2065 100644 --- a/apps/routerconsole/jsp/configclients.jsp +++ b/apps/routerconsole/jsp/configclients.jsp @@ -26,7 +26,7 @@ button span.hide{ " /> -
    +
    <% String prev = System.getProperty("net.i2p.router.web.ConfigClientsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigClientsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigClientsHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configkeyring.jsp b/apps/routerconsole/jsp/configkeyring.jsp index dc265ba1b5..01c332b495 100644 --- a/apps/routerconsole/jsp/configkeyring.jsp +++ b/apps/routerconsole/jsp/configkeyring.jsp @@ -25,7 +25,7 @@

    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigKeyringHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigKeyringHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigKeyringHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configlogging.jsp b/apps/routerconsole/jsp/configlogging.jsp index ca30423dc2..a90c362d73 100644 --- a/apps/routerconsole/jsp/configlogging.jsp +++ b/apps/routerconsole/jsp/configlogging.jsp @@ -19,7 +19,7 @@ " />
    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigLoggingHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigLoggingHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigLoggingHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configpeer.jsp b/apps/routerconsole/jsp/configpeer.jsp index bd53901089..0dfb550851 100644 --- a/apps/routerconsole/jsp/configpeer.jsp +++ b/apps/routerconsole/jsp/configpeer.jsp @@ -27,7 +27,7 @@ peer = net.i2p.data.DataHelper.stripHTML(request.getParameter("peer")); // XSS %>
    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigPeerHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigPeerHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigPeerHandler.nonce", new java.util.Random().nextLong()+""); %> @@ -49,7 +49,7 @@

    <%=intl._("Adjust Profile Bonuses")%>

    -

    <%=intl._("Bonuses may be positive or negative, and affect the peer's inclusion in Fast and High Capacity tiers. Fast peers are used for client tunnels, and High Capacity peers are used for some exploratory tunnels. Current bonuses are displayed on the")%> <%=intl._("profiles page")%>.

    +

    <%=intl._("Bonuses may be positive or negative, and affect the peer's inclusion in Fast and High Capacity tiers. Fast peers are used for client tunnels, and High Capacity peers are used for some exploratory tunnels. Current bonuses are displayed on the")%> <%=intl._("profiles page")%>.

    <% long speed = 0; long capacity = 0; if (! "".equals(peer)) { // get existing bonus values? diff --git a/apps/routerconsole/jsp/configservice.jsp b/apps/routerconsole/jsp/configservice.jsp index c0554dfa05..d71c8ee399 100644 --- a/apps/routerconsole/jsp/configservice.jsp +++ b/apps/routerconsole/jsp/configservice.jsp @@ -17,7 +17,7 @@ " />
    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigServiceHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigServiceHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigServiceHandler.nonce", new java.util.Random().nextLong()+""); %> @@ -60,7 +60,7 @@ <% } %>

    <%=intl._("Debugging")%>

    -

    <%=intl._("View the job queue")%> +

    <%=intl._("View the job queue")%> <% if (System.getProperty("wrapper.version") != null) { %>

    <%=intl._("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 wrapper.log.")%>


    @@ -70,7 +70,7 @@

    <%=intl._("Launch browser on router startup?")%>

    <%=intl._("I2P's main configuration interface is this web console, so for your convenience I2P can launch a web browser on startup pointing at")%> - http://127.0.0.1:7657/index.jsp .

    + http://127.0.0.1:7657/ .


    " > " > diff --git a/apps/routerconsole/jsp/configstats.jsp b/apps/routerconsole/jsp/configstats.jsp index 20db1726cb..1f3dd6354d 100644 --- a/apps/routerconsole/jsp/configstats.jsp +++ b/apps/routerconsole/jsp/configstats.jsp @@ -65,7 +65,7 @@ function toggleAll(category) " />
    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigStatsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigStatsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigStatsHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configtunnels.jsp b/apps/routerconsole/jsp/configtunnels.jsp index d505b741a9..9a6a11a378 100644 --- a/apps/routerconsole/jsp/configtunnels.jsp +++ b/apps/routerconsole/jsp/configtunnels.jsp @@ -29,7 +29,7 @@ <%=intl._("High CPU and/or high outbound bandwidth usage may result.")%> <%=intl._("Change these settings with care, and adjust them if you have problems.")%>
    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigTunnelsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigTunnelsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigTunnelsHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configui.jsp b/apps/routerconsole/jsp/configui.jsp index 19cd125fa5..f2a0f5b0fc 100644 --- a/apps/routerconsole/jsp/configui.jsp +++ b/apps/routerconsole/jsp/configui.jsp @@ -22,7 +22,7 @@ " />

    <%=uihelper._("Router Console Theme")%>

    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigUIHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigUIHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigUIHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index 22432f60ac..21ae4fedff 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -21,7 +21,7 @@
    - + <% String prev = System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %> From af4a285e5b29b28f0884e729d8bbc7fb5e72c6d1 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 15:32:31 +0000 Subject: [PATCH 12/19] fix small confignav problem --- .../java/src/net/i2p/router/web/ConfigNavHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java index 44204f66d8..c97647fc97 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java @@ -23,7 +23,7 @@ public class ConfigNavHelper extends HelperBase { StringBuilder buf = new StringBuilder(1024); for (int i = 0; i < pages.length; i++) { String page = "config" + pages[i]; - if (requestURI.indexOf(page) != -1) { + if (requestURI.endsWith(page) || requestURI.endsWith(page + ".jsp")) { // we are there buf.append(_(titles[i])); } else { From dd39f3f2447e6beeb0dcd41d93c1ad5ff9adb049 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 19 Nov 2010 16:14:14 +0000 Subject: [PATCH 13/19] i2ptunnel jsp cleanup --- apps/i2ptunnel/jsp/editClient.jsp | 2 +- apps/i2ptunnel/jsp/editServer.jsp | 2 +- apps/i2ptunnel/jsp/index.html | 2 -- apps/i2ptunnel/jsp/index.jsp | 26 +++++++++---------- apps/i2ptunnel/jsp/web.xml | 13 ++++++++++ .../i2p/router/web/SummaryBarRenderer.java | 2 +- .../src/net/i2p/router/web/SummaryHelper.java | 2 +- apps/routerconsole/jsp/configkeyring.jsp | 2 +- 8 files changed, 31 insertions(+), 20 deletions(-) delete mode 100644 apps/i2ptunnel/jsp/index.html diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp index be48bb2b92..2b69440ac1 100644 --- a/apps/i2ptunnel/jsp/editClient.jsp +++ b/apps/i2ptunnel/jsp/editClient.jsp @@ -29,7 +29,7 @@ - +
    diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp index 97a0a93c9c..773d323a2b 100644 --- a/apps/i2ptunnel/jsp/editServer.jsp +++ b/apps/i2ptunnel/jsp/editServer.jsp @@ -29,7 +29,7 @@ - +
    diff --git a/apps/i2ptunnel/jsp/index.html b/apps/i2ptunnel/jsp/index.html deleted file mode 100644 index ea1321105e..0000000000 --- a/apps/i2ptunnel/jsp/index.html +++ /dev/null @@ -1,2 +0,0 @@ -I2P Router Console -Enter diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp index 8b7f8051ea..cf0d0067c3 100644 --- a/apps/i2ptunnel/jsp/index.jsp +++ b/apps/i2ptunnel/jsp/index.jsp @@ -44,7 +44,7 @@
    @@ -53,7 +53,7 @@
    @@ -89,7 +89,7 @@ %>
    @@ -125,17 +125,17 @@ switch (indexBean.getTunnelStatus(curServer)) { case IndexBean.STARTING: %>
    <%=intl._("Starting...")%>
    - <%=intl._("Stop")%> + <%=intl._("Stop")%> <% break; case IndexBean.RUNNING: %>
    <%=intl._("Running")%>
    - <%=intl._("Stop")%> + <%=intl._("Stop")%> <% break; case IndexBean.NOT_RUNNING: %>
    <%=intl._("Stopped")%>
    - <%=intl._("Start")%> + <%=intl._("Start")%> <% break; } @@ -157,7 +157,7 @@