diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 66b372d61..44410d7cb 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -112,7 +112,7 @@ public class SnarkManager implements CompleteListener { * "name", "announceURL=websiteURL" pairs * '=' in announceURL must be escaped as , */ - public static final String DEFAULT_TRACKERS[] = { + private static final String DEFAULT_TRACKERS[] = { // "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/" // , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/" // , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/" @@ -129,6 +129,17 @@ public class SnarkManager implements CompleteListener { // ,"Exotrack", "http://blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva.b32.i2p/announce.php=http://exotrack.i2p/" }; + public static final Set DEFAULT_TRACKER_ANNOUNCES; + + static { + Set ann = new HashSet(); + for (int i = 1; i < DEFAULT_TRACKERS.length; i += 2) { + String urls[] = DEFAULT_TRACKERS[i].split("=", 2); + ann.add(urls[0]); + } + DEFAULT_TRACKER_ANNOUNCES = Collections.unmodifiableSet(ann); + } + /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ public static final String PROP_TRACKERS = "i2psnark.trackers"; 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 5606a6186..e5f2d8647 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -2007,12 +2007,8 @@ public class I2PSnarkServlet extends BasicServlet { if (privateTrackers.contains(t.announceURL)) { buf.append(" checked=\"checked\""); } else { - for (int i = 1; i < SnarkManager.DEFAULT_TRACKERS.length; i += 2) { - if (SnarkManager.DEFAULT_TRACKERS[i].contains(t.announceURL)) { - buf.append(" disabled=\"disabled\""); - break; - } - } + if (SnarkManager.DEFAULT_TRACKER_ANNOUNCES.contains(t.announceURL)) + buf.append(" disabled=\"disabled\""); } buf.append(">" + "").append(urlify(announceURL, 35)) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java index c0e4c6693..e4f47cdaf 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSink.java @@ -1,11 +1,5 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; -// i2p import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; import net.i2p.data.Destination; @@ -19,17 +13,23 @@ import net.i2p.client.datagram.I2PDatagramMaker; * @author welterde */ public class I2PSink implements Sink { + public I2PSink(I2PSession sess, Destination dest) { this(sess, dest, false); } + public I2PSink(I2PSession sess, Destination dest, boolean raw) { this.sess = sess; this.dest = dest; this.raw = raw; // create maker - if (!raw) + if (raw) { + this.maker = null; + } else { + this.maker = new I2PDatagramMaker(); this.maker.setI2PDatagramMaker(this.sess); + } } /** @param src ignored */ @@ -46,7 +46,8 @@ public class I2PSink implements Sink { // send message try { - this.sess.sendMessage(this.dest, payload, I2PSession.PROTO_DATAGRAM, + this.sess.sendMessage(this.dest, payload, + (this.raw ? I2PSession.PROTO_DATAGRAM_RAW : I2PSession.PROTO_DATAGRAM), I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); } catch(I2PSessionException exc) { // TODO: handle better @@ -54,8 +55,8 @@ public class I2PSink implements Sink { } } - protected boolean raw; - protected I2PSession sess; - protected Destination dest; - protected final I2PDatagramMaker maker= new I2PDatagramMaker(); // FIXME should be final and use a factory. FIXME + protected final boolean raw; + protected final I2PSession sess; + protected final Destination dest; + protected final I2PDatagramMaker maker; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java index a2793e7dd..e33d93d10 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSinkAnywhere.java @@ -1,11 +1,5 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; -// i2p import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; import net.i2p.data.Destination; @@ -19,16 +13,22 @@ import net.i2p.client.datagram.I2PDatagramMaker; * @author zzz modded from I2PSink by welterde */ public class I2PSinkAnywhere implements Sink { + public I2PSinkAnywhere(I2PSession sess) { this(sess, false); } + public I2PSinkAnywhere(I2PSession sess, boolean raw) { this.sess = sess; this.raw = raw; // create maker - if (!raw) + if (raw) { + this.maker = null; + } else { + this.maker = new I2PDatagramMaker(); this.maker.setI2PDatagramMaker(this.sess); + } } /** @param to - where it's going */ @@ -44,7 +44,8 @@ public class I2PSinkAnywhere implements Sink { // send message try { - this.sess.sendMessage(to, payload, I2PSession.PROTO_DATAGRAM, + this.sess.sendMessage(to, payload, + (this.raw ? I2PSession.PROTO_DATAGRAM_RAW : I2PSession.PROTO_DATAGRAM), I2PSession.PORT_UNSPECIFIED, I2PSession.PORT_UNSPECIFIED); } catch(I2PSessionException exc) { // TODO: handle better @@ -52,8 +53,7 @@ public class I2PSinkAnywhere implements Sink { } } - protected boolean raw; - protected I2PSession sess; - protected Destination dest; - protected final I2PDatagramMaker maker = new I2PDatagramMaker(); + protected final boolean raw; + protected final I2PSession sess; + protected final I2PDatagramMaker maker; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java index 04a8bde6a..68a9d90a2 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/I2PSource.java @@ -1,15 +1,8 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; -// system import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; -// i2p import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionListener; import net.i2p.client.datagram.I2PDatagramDissector; @@ -19,15 +12,17 @@ import net.i2p.client.datagram.I2PDatagramDissector; * @author welterde */ public class I2PSource implements Source, Runnable { + public I2PSource(I2PSession sess) { this(sess, true, false); } + public I2PSource(I2PSession sess, boolean verify) { this(sess, verify, false); } + public I2PSource(I2PSession sess, boolean verify, boolean raw) { this.sess = sess; - this.sink = null; this.verify = verify; this.raw = raw; @@ -80,11 +75,6 @@ public class I2PSource implements Source, Runnable { } } - - - - - protected class Listener implements I2PSessionListener { public void messageAvailable(I2PSession sess, int id, long size) { @@ -109,15 +99,10 @@ public class I2PSource implements Source, Runnable { } - - - - - - protected I2PSession sess; - protected BlockingQueue queue; + protected final I2PSession sess; + protected final BlockingQueue queue; protected Sink sink; - protected Thread thread; - protected boolean verify; - protected boolean raw; + protected final Thread thread; + protected final boolean verify; + protected final boolean raw; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java index 49e3e47a3..a3ddc6b84 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Sink.java @@ -1,11 +1,5 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; -// i2p import net.i2p.data.Destination; /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java index f65d03b19..c1929cfe7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Source.java @@ -1,8 +1,3 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java index b8b57e696..f0a79a801 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/Stream.java @@ -1,8 +1,3 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java index d2e8e8924..0b5905ad7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSink.java @@ -1,16 +1,9 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; -// system import java.net.DatagramSocket; import java.net.DatagramPacket; import java.net.InetAddress; -// i2p import net.i2p.data.Destination; /** @@ -18,6 +11,7 @@ import net.i2p.data.Destination; * @author welterde */ public class UDPSink implements Sink { + public UDPSink(InetAddress host, int port) { // create socket try { @@ -61,17 +55,8 @@ public class UDPSink implements Sink { this.sock.close(); } - - - - - - - - - - protected DatagramSocket sock; - protected InetAddress remoteHost; - protected int remotePort; + protected final DatagramSocket sock; + protected final InetAddress remoteHost; + protected final int remotePort; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java index fc1dd5bf2..6f1a20e5f 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/udp/UDPSource.java @@ -1,11 +1,5 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ - package net.i2p.i2ptunnel.udp; -// system import java.net.DatagramSocket; import java.net.DatagramPacket; @@ -15,9 +9,8 @@ import java.net.DatagramPacket; */ public class UDPSource implements Source, Runnable { public static final int MAX_SIZE = 15360; + public UDPSource(int port) { - this.sink = null; - // create udp-socket try { this.sock = new DatagramSocket(port); @@ -31,7 +24,6 @@ public class UDPSource implements Source, Runnable { /** use socket from UDPSink */ public UDPSource(DatagramSocket sock) { - this.sink = null; this.sock = sock; this.thread = new Thread(this); } @@ -73,19 +65,7 @@ public class UDPSource implements Source, Runnable { this.sock.close(); } - - - - - - - - - - - - - protected DatagramSocket sock; + protected final DatagramSocket sock; protected Sink sink; - protected Thread thread; + protected final Thread thread; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java index a0ae4a533..e0be9d2f8 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java @@ -1,5 +1,7 @@ package net.i2p.router.web; +import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -49,15 +51,30 @@ public class CSSHelper extends HelperBase { return url; } - /** change default language for the router AND save it */ + /** + * change default language for the router AND save it + * @param lang xx OR xx_XX + */ public void setLang(String lang) { // Protected with nonce in css.jsi - if (lang != null && lang.length() == 2 && !lang.equals(_context.getProperty(Messages.PROP_LANG))) { - _context.router().saveConfig(Messages.PROP_LANG, lang); + if (lang != null) { + Map m = new HashMap(2); + if (lang.length() == 2) { + m.put(Messages.PROP_LANG, lang.toLowerCase(Locale.US)); + m.put(Messages.PROP_COUNTRY, ""); + _context.router().saveConfig(m, null); + } else if (lang.length() == 5) { + m.put(Messages.PROP_LANG, lang.substring(0, 2).toLowerCase(Locale.US)); + m.put(Messages.PROP_COUNTRY, lang.substring(3, 5).toUpperCase(Locale.US)); + _context.router().saveConfig(m, null); + } } } - /** needed for conditional css loads for zh */ + /** + * needed for conditional css loads for zh + * @return two-letter only, lower-case + */ public String getLang() { return Messages.getLanguage(_context); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java index 7b406fbff..4bd526bee 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java @@ -65,36 +65,66 @@ public class ConfigUIHelper extends HelperBase { } /** - * Each language has the ISO code, the flag, and the name. + * Each language has the ISO code, the flag, the name, and the optional country name. * Alphabetical by the ISO code please. * See http://en.wikipedia.org/wiki/ISO_639-1 . * Any language-specific flag added to the icon set must be * added to the top-level build.xml for the updater. */ - private static final String langs[] = {"ar", "cs", "da", "de", "et", "el", "en", "es", "fi", - "fr", "hu", "it", "ja", "nb", "nl", "pl", "pt", "ro", "ru", - "sv", "tr", "uk", "vi", "zh"}; - private static final String flags[] = {"lang_ar", "cz", "dk", "de", "ee", "gr", "us", "es", "fi", - "fr", "hu", "it", "jp", "nl", "no", "pl", "pt", "ro", "ru", - "se", "tr", "ua", "vn", "cn"}; - private static final String xlangs[] = {_x("Arabic"), _x("Czech"), _x("Danish"), - _x("German"), _x("Estonian"), _x("Greek"), _x("English"), _x("Spanish"), _x("Finnish"), - _x("French"), _x("Hungarian"), _x("Italian"), _x("Japanese"), _x("Dutch"), _x("Norwegian Bokmaal"), _x("Polish"), - _x("Portuguese"), _x("Romanian"), _x("Russian"), _x("Swedish"), - _x("Turkish"), _x("Ukrainian"), _x("Vietnamese"), _x("Chinese")}; + private static final String langs[][] = { + { "ar", "lang_ar", _x("Arabic"), null }, + { "cs", "cz", _x("Czech"), null }, + { "da", "dk", _x("Danish"), null }, + { "de", "de", _x("German"), null }, + { "et", "ee", _x("Estonian"), null }, + { "el", "gr", _x("Greek"), null }, + { "en", "us", _x("English"), null }, + { "es", "es", _x("Spanish"), null }, + { "fi", "fi", _x("Finnish"), null }, + { "fr", "fr", _x("French"), null }, + { "hu", "hu", _x("Hungarian"), null }, + { "it", "it", _x("Italian"), null }, + { "ja", "jp", _x("Japanese"), null }, + { "nb", "nl", _x("Dutch"), null }, + { "nl", "no", _x("Norwewgian Bokmaal"), null }, + { "pl", "pl", _x("Polish"), null }, + { "pt", "pt", _x("Portuguese"), null }, + // { "pt_BR", "br", _x("Portuguese"), "Brazil" }, + { "ro", "ro", _x("Romainian"), null }, + { "ru", "ru", _x("Russian"), null }, + { "sv", "se", _x("Swedish"), null }, + { "tr", "tr", _x("Turkish"), null }, + { "uk", "ua", _x("Ukrainian"), null }, + { "vi", "vn", _x("Vietnamese"), null }, + { "zh", "cn", _x("Chinese"), null } + }; + + /** todo sort by translated string */ public String getLangSettings() { StringBuilder buf = new StringBuilder(512); String current = Messages.getLanguage(_context); + String country = Messages.getCountry(_context); + if (country != null && country.length() > 0) + current += '_' + country; for (int i = 0; i < langs.length; i++) { // we use "lang" so it is set automagically in CSSHelper buf.append("") - .append("\"\" ") - .append(Messages.getDisplayLanguage(langs[i], xlangs[i], _context)).append("
\n"); + buf.append("value=\"").append(lang).append("\">") + .append("\"\" "); + String slang = lang.length() > 2 ? lang.substring(0, 2) : lang; + buf.append(Messages.getDisplayLanguage(slang, langs[i][2], _context)); + String name = langs[i][3]; + if (name != null) { + buf.append(" (") + .append(Messages.getString(name, _context, Messages.COUNTRY_BUNDLE_NAME)) + .append(')'); + } + buf.append("
\n"); } return buf.toString(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/Messages.java b/apps/routerconsole/java/src/net/i2p/router/web/Messages.java index 7becafbe9..c76f260e8 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/Messages.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/Messages.java @@ -9,6 +9,8 @@ import net.i2p.util.Translate; public class Messages extends Translate { private static final String BUNDLE_NAME = "net.i2p.router.web.messages"; + static final String COUNTRY_BUNDLE_NAME = "net.i2p.router.countries.messages"; + /** lang in routerconsole.lang property, else current locale */ public static String getString(String key, I2PAppContext ctx) { return Translate.getString(key, ctx, BUNDLE_NAME); 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 5dafe42a5..1e49beea1 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -350,8 +350,6 @@ public class NetDbRenderer { out.flush(); } - private static final String COUNTRY_BUNDLE_NAME = "net.i2p.router.countries.messages"; - /** * Countries now in a separate bundle * @param code two-letter country code @@ -359,7 +357,7 @@ public class NetDbRenderer { */ private String getTranslatedCountry(String code) { String name = _context.commSystem().getCountryName(code); - return Translate.getString(name, _context, COUNTRY_BUNDLE_NAME); + return Translate.getString(name, _context, Messages.COUNTRY_BUNDLE_NAME); } /** sort by translated country name using rules for the current language setting */ diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java index ee2274985..0d756fa95 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java @@ -252,6 +252,8 @@ public class SummaryBarRenderer { .append(_("Addressbook")) .append("\n"); + if (_context.getBooleanProperty(HelperBase.PROP_ADVANCED)) + buf.append("Debug\n"); File javadoc = new File(_context.getBaseDir(), "docs/javadoc/index.html"); if (javadoc.exists()) buf.append("Javadoc\n"); diff --git a/core/java/src/net/i2p/crypto/DummyDSAEngine.java b/core/java/src/net/i2p/crypto/DummyDSAEngine.java index 3a35a9629..b8e7e1934 100644 --- a/core/java/src/net/i2p/crypto/DummyDSAEngine.java +++ b/core/java/src/net/i2p/crypto/DummyDSAEngine.java @@ -10,6 +10,9 @@ import net.i2p.data.SigningPublicKey; * */ public class DummyDSAEngine extends DSAEngine { + + private static final Signature FAKE_SIGNATURE = new Signature(new byte[Signature.SIGNATURE_BYTES]); + public DummyDSAEngine(I2PAppContext context) { super(context); } @@ -21,8 +24,6 @@ public class DummyDSAEngine extends DSAEngine { @Override public Signature sign(byte data[], SigningPrivateKey signingKey) { - Signature sig = new Signature(); - sig.setData(Signature.FAKE_SIGNATURE); - return sig; + return FAKE_SIGNATURE; } -} \ No newline at end of file +} diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 83fe675ff..9229ed851 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -399,6 +399,7 @@ public class DataHelper { * - Leading whitespace is not trimmed * - '=' is the only key-termination character (not ':' or whitespace) * + * As of 0.9.10, an empty value is allowed. */ public static void loadProps(Properties props, File file) throws IOException { loadProps(props, file, false); @@ -442,11 +443,12 @@ public class DataHelper { // it was a horrible idea anyway //val = val.replaceAll("\\\\r","\r"); //val = val.replaceAll("\\\\n","\n"); - if ( (key.length() > 0) && (val.length() > 0) ) - if (forceLowerCase) - props.setProperty(key.toLowerCase(Locale.US), val); - else - props.setProperty(key, val); + + // as of 0.9.10, an empty value is allowed + if (forceLowerCase) + props.setProperty(key.toLowerCase(Locale.US), val); + else + props.setProperty(key, val); } } finally { if (in != null) try { in.close(); } catch (IOException ioe) {} diff --git a/core/java/src/net/i2p/data/Signature.java b/core/java/src/net/i2p/data/Signature.java index 55b60c7a9..83f0410e2 100644 --- a/core/java/src/net/i2p/data/Signature.java +++ b/core/java/src/net/i2p/data/Signature.java @@ -25,7 +25,11 @@ public class Signature extends SimpleDataStructure { private static final SigType DEF_TYPE = SigType.DSA_SHA1; /** 40 */ public final static int SIGNATURE_BYTES = DEF_TYPE.getSigLen(); - /** all zeros */ + + /** + * all zeros + * @deprecated to be removed + */ public final static byte[] FAKE_SIGNATURE = new byte[SIGNATURE_BYTES]; private final SigType _type; diff --git a/core/java/src/net/i2p/util/Translate.java b/core/java/src/net/i2p/util/Translate.java index 86e9c4e6e..632658cb1 100644 --- a/core/java/src/net/i2p/util/Translate.java +++ b/core/java/src/net/i2p/util/Translate.java @@ -25,7 +25,12 @@ import net.i2p.util.ConcurrentHashSet; */ public abstract class Translate { public static final String PROP_LANG = "routerconsole.lang"; + /** @since 0.9.10 */ + public static final String PROP_COUNTRY = "routerconsole.country"; + /** non-null, two-letter lower case, may be "" */ private static final String _localeLang = Locale.getDefault().getLanguage(); + /** non-null, two-letter upper case, may be "" */ + private static final String _localeCountry = Locale.getDefault().getCountry(); private static final Map _bundles = new ConcurrentHashMap(16); private static final Set _missing = new ConcurrentHashSet(16); /** use to look for untagged strings */ @@ -42,7 +47,7 @@ public abstract class Translate { // shouldnt happen but dont dump the po headers if it does if (key.equals("")) return key; - ResourceBundle bundle = findBundle(bun, lang); + ResourceBundle bundle = findBundle(bun, lang, getCountry(ctx)); if (bundle == null) return key; try { @@ -110,7 +115,7 @@ public abstract class Translate { return TEST_STRING + '(' + n + ')' + TEST_STRING; ResourceBundle bundle = null; if (!lang.equals("en")) - bundle = findBundle(bun, lang); + bundle = findBundle(bun, lang, getCountry(ctx)); String x; if (bundle == null) x = n == 1 ? s : p; @@ -129,7 +134,10 @@ public abstract class Translate { } } - /** @return lang in routerconsole.lang property, else current locale */ + /** + * Two-letter lower case + * @return lang in routerconsole.lang property, else current locale + */ public static String getLanguage(I2PAppContext ctx) { String lang = ctx.getProperty(PROP_LANG); if (lang == null || lang.length() <= 0) @@ -137,14 +145,39 @@ public abstract class Translate { return lang; } - /** cache both found and not found for speed */ - private static ResourceBundle findBundle(String bun, String lang) { - String key = bun + '-' + lang; + /** + * Two-letter upper case or "" + * @return country in routerconsole.country property, else current locale + * @since 0.9.10 + */ + public static String getCountry(I2PAppContext ctx) { + // property may be empty so we don't have a non-default + // language and a default country + return ctx.getProperty(PROP_COUNTRY, _localeCountry); + } + + /** + * cache both found and not found for speed + * @param lang non-null, if "" returns null + * @param country non-null, may be "" + * @return null if not found + */ + private static ResourceBundle findBundle(String bun, String lang, String country) { + String key = bun + '-' + lang + '-' + country; ResourceBundle rv = _bundles.get(key); if (rv == null && !_missing.contains(key)) { + if ("".equals(lang)) { + _missing.add(key); + return null; + } try { + Locale loc; + if ("".equals(country)) + loc = new Locale(lang); + else + loc = new Locale(lang, country); // We must specify the class loader so that a webapp can find the bundle in the .war - rv = ResourceBundle.getBundle(bun, new Locale(lang), Thread.currentThread().getContextClassLoader()); + rv = ResourceBundle.getBundle(bun, loc, Thread.currentThread().getContextClassLoader()); if (rv != null) _bundles.put(key, rv); } catch (MissingResourceException e) { diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 4d10f938f..ebdcdc163 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -229,13 +229,28 @@ public class Router implements RouterClock.ClockShiftListener { // for the ping file // Check for other router but do not start a thread yet so the update doesn't cause // a NCDFE - if (!isOnlyRouterRunning()) { - _eventLog.addEvent(EventLog.ABORTED, "Another router running"); - System.err.println("ERROR: There appears to be another router already running!"); - System.err.println(" Please make sure to shut down old instances before starting up"); - System.err.println(" a new one. If you are positive that no other instance is running,"); - System.err.println(" please delete the file " + getPingFile().getAbsolutePath()); - System.exit(-1); + for (int i = 0; i < 14; i++) { + // Wrapper can start us up too quickly after a crash, the ping file + // may still be less than LIVELINESS_DELAY (60s) old. + // So wait at least 60s to be sure. + if (isOnlyRouterRunning()) { + if (i > 0) + System.err.println("INFO: No, there wasn't another router already running. Proceeding with startup."); + break; + } + if (i < 13) { + if (i == 0) + System.err.println("WARN: There may be another router already running. Waiting a while to be sure..."); + // yes this is ugly to sleep in the constructor. + try { Thread.sleep(5000); } catch (InterruptedException ie) {} + } else { + _eventLog.addEvent(EventLog.ABORTED, "Another router running"); + System.err.println("ERROR: There appears to be another router already running!"); + System.err.println(" Please make sure to shut down old instances before starting up"); + System.err.println(" a new one. If you are positive that no other instance is running,"); + System.err.println(" please delete the file " + getPingFile().getAbsolutePath()); + System.exit(-1); + } } if (_config.get("router.firstVersion") == null) { diff --git a/router/java/src/net/i2p/router/peermanager/PeerManager.java b/router/java/src/net/i2p/router/peermanager/PeerManager.java index 904ca8bdb..ef7b1de34 100644 --- a/router/java/src/net/i2p/router/peermanager/PeerManager.java +++ b/router/java/src/net/i2p/router/peermanager/PeerManager.java @@ -25,6 +25,7 @@ import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.util.ConcurrentHashSet; +import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.SimpleTimer2; @@ -89,6 +90,24 @@ class PeerManager { super(_context.simpleTimer2(), REORGANIZE_TIME); } public void timeReached() { + (new ReorgThread(this)).start(); + } + } + + /** + * This takes too long to run on the SimpleTimer2 queue + * @since 0.9.10 + */ + private class ReorgThread extends I2PThread { + private SimpleTimer2.TimedEvent _event; + + public ReorgThread(SimpleTimer2.TimedEvent event) { + super("PeerManager Reorg"); + setDaemon(true); + _event = event; + } + + public void run() { long start = System.currentTimeMillis(); try { _organizer.reorganize(true); @@ -104,7 +123,7 @@ class PeerManager { delay = REORGANIZE_TIME_MEDIUM; else delay = REORGANIZE_TIME; - schedule(delay); + _event.schedule(delay); } } diff --git a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java index 88ad248d7..53053b6d2 100644 --- a/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java +++ b/router/java/src/net/i2p/router/transport/CommSystemFacadeImpl.java @@ -26,6 +26,7 @@ import net.i2p.router.RouterContext; import net.i2p.router.transport.udp.UDPTransport; import net.i2p.router.util.EventLog; import net.i2p.util.Addresses; +import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.SimpleTimer; import net.i2p.util.SimpleTimer2; @@ -223,6 +224,7 @@ public class CommSystemFacadeImpl extends CommSystemFacade { /* We hope the routerinfos are read in and things have settled down by now, but it's not required to be so */ private static final int START_DELAY = 5*60*1000; private static final int LOOKUP_TIME = 30*60*1000; + private void startGeoIP() { _context.simpleScheduler().addEvent(new QueueAll(), START_DELAY); } @@ -248,7 +250,26 @@ public class CommSystemFacadeImpl extends CommSystemFacade { private class Lookup implements SimpleTimer.TimedEvent { public void timeReached() { + (new LookupThread()).start(); + } + } + + /** + * This takes too long to run on the SimpleTimer2 queue + * @since 0.9.10 + */ + private class LookupThread extends I2PThread { + + public LookupThread() { + super("GeoIP Lookup"); + setDaemon(true); + } + + public void run() { + long start = System.currentTimeMillis(); _geoIP.blockingLookup(); + if (_log.shouldLog(Log.INFO)) + _log.info("GeoIP lookup took " + (System.currentTimeMillis() - start)); } } diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java index 063d5f1d4..43cdba3ba 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java @@ -211,7 +211,7 @@ class EventPumper implements Runnable { int failsafeInvalid = 0; // Increase allowed idle time if we are well under allowed connections, otherwise decrease - if (_transport.haveCapacity(60)) + if (_transport.haveCapacity(45)) _expireIdleWriteTime = Math.min(_expireIdleWriteTime + 1000, MAX_EXPIRE_IDLE_TIME); else _expireIdleWriteTime = Math.max(_expireIdleWriteTime - 3000, MIN_EXPIRE_IDLE_TIME); diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java index feb471abb..06a440ada 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -11,6 +11,7 @@ import java.util.Map; import java.util.Set; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; import net.i2p.data.Hash; import net.i2p.data.SessionKey; @@ -119,9 +120,9 @@ class PeerState { */ //private boolean _remoteWantsPreviousACKs; /** how many bytes should we send to the peer in a second */ - private volatile int _sendWindowBytes; + private int _sendWindowBytes; /** how many bytes can we send to the peer in the current second */ - private volatile int _sendWindowBytesRemaining; + private int _sendWindowBytesRemaining; private long _lastSendRefill; private int _sendBps; private int _sendBytes; @@ -225,13 +226,13 @@ class PeerState { /** Make sure a 4229 byte TunnelBuildMessage can be sent in one volley with small MTU */ private static final int MIN_CONCURRENT_MSGS = 8; /** how many concurrent outbound messages do we allow throws OutboundMessageFragments to send */ - private volatile int _concurrentMessagesAllowed = MIN_CONCURRENT_MSGS; + private int _concurrentMessagesAllowed = MIN_CONCURRENT_MSGS; /** * how many outbound messages are currently being transmitted. Not thread safe, as we're not strict */ - private volatile int _concurrentMessagesActive = 0; + private int _concurrentMessagesActive; /** how many concurrency rejections have we had in a row */ - private volatile int _consecutiveRejections = 0; + private int _consecutiveRejections; /** is it inbound? **/ private final boolean _isInbound; /** Last time it was made an introducer **/ @@ -436,9 +437,19 @@ class PeerState { //public boolean getRemoteWantsPreviousACKs() { return _remoteWantsPreviousACKs; } /** how many bytes should we send to the peer in a second */ - public int getSendWindowBytes() { return _sendWindowBytes; } + public int getSendWindowBytes() { + synchronized(_outboundMessages) { + return _sendWindowBytes; + } + } + /** how many bytes can we send to the peer in the current second */ - public int getSendWindowBytesRemaining() { return _sendWindowBytesRemaining; } + public int getSendWindowBytesRemaining() { + synchronized(_outboundMessages) { + return _sendWindowBytesRemaining; + } + } + /** what IP is the peer sending and receiving packets on? */ public byte[] getRemoteIP() { return _remoteIP; } @@ -580,20 +591,24 @@ class PeerState { /** return the smoothed send transfer rate */ public int getSendBps() { return _sendBps; } public int getReceiveBps() { return _receiveBps; } + public int incrementConsecutiveFailedSends() { - _concurrentMessagesActive--; - if (_concurrentMessagesActive < 0) - _concurrentMessagesActive = 0; - - //long now = _context.clock().now()/(10*1000); - //if (_lastFailedSendPeriod >= now) { - // // ignore... too fast - //} else { - // _lastFailedSendPeriod = now; - _consecutiveFailedSends++; - //} - return _consecutiveFailedSends; + synchronized(_outboundMessages) { + _concurrentMessagesActive--; + if (_concurrentMessagesActive < 0) + _concurrentMessagesActive = 0; + + //long now = _context.clock().now()/(10*1000); + //if (_lastFailedSendPeriod >= now) { + // // ignore... too fast + //} else { + // _lastFailedSendPeriod = now; + _consecutiveFailedSends++; + //} + return _consecutiveFailedSends; + } } + public long getInactivityTime() { long now = _context.clock().now(); long lastActivity = Math.max(_lastReceiveTime, _lastSendFullyTime); @@ -620,15 +635,17 @@ class PeerState { * returning true if the full size can be decremented, false if it * cannot. If it is not decremented, the window size remaining is * not adjusted at all. + * + * Caller should synch */ - public boolean allocateSendingBytes(int size, int messagePushCount) { return allocateSendingBytes(size, false, messagePushCount); } + private boolean allocateSendingBytes(int size, int messagePushCount) { return allocateSendingBytes(size, false, messagePushCount); } - public boolean allocateSendingBytes(int size, boolean isForACK) { return allocateSendingBytes(size, isForACK, -1); } + //private boolean allocateSendingBytes(int size, boolean isForACK) { return allocateSendingBytes(size, isForACK, -1); } /** * Caller should synch */ - public boolean allocateSendingBytes(int size, boolean isForACK, int messagePushCount) { + private boolean allocateSendingBytes(int size, boolean isForACK, int messagePushCount) { long now = _context.clock().now(); long duration = now - _lastSendRefill; if (duration >= 1000) { @@ -694,9 +711,25 @@ class PeerState { ****/ public int getSlowStartThreshold() { return _slowStartThreshold; } - public int getConcurrentSends() { return _concurrentMessagesActive; } - public int getConcurrentSendWindow() { return _concurrentMessagesAllowed; } - public int getConsecutiveSendRejections() { return _consecutiveRejections; } + + public int getConcurrentSends() { + synchronized(_outboundMessages) { + return _concurrentMessagesActive; + } + } + + public int getConcurrentSendWindow() { + synchronized(_outboundMessages) { + return _concurrentMessagesAllowed; + } + } + + public int getConsecutiveSendRejections() { + synchronized(_outboundMessages) { + return _consecutiveRejections; + } + } + public boolean isInbound() { return _isInbound; } /** @since IPv6 */ @@ -1674,6 +1707,8 @@ class PeerState { /** * Have 3 return values, because if allocateSendingBytes() returns false, * then allocateSend() can stop iterating + * + * Caller should synch */ private ShouldSend locked_shouldSend(OutboundMessageState state) { long now = _context.clock().now(); 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 062e75686..2ce631ab1 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -2848,7 +2848,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority public void timeReached() { // Increase allowed idle time if we are well under allowed connections, otherwise decrease - if (haveCapacity(60)) { + if (haveCapacity(45)) { long inc; // don't adjust too quickly if we are looping fast if (_lastLoopShort)