From cf463100cd180293375f90aa93a281e13f0f5f07 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 18 Feb 2012 15:22:40 +0000 Subject: [PATCH 01/44] stub out private mode --- .../java/src/org/klomp/snark/MetaInfo.java | 22 +++++++++++++++++-- .../java/src/org/klomp/snark/Storage.java | 5 +++-- .../org/klomp/snark/web/I2PSnarkServlet.java | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/MetaInfo.java b/apps/i2psnark/java/src/org/klomp/snark/MetaInfo.java index 28677addaf..648a055243 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/MetaInfo.java +++ b/apps/i2psnark/java/src/org/klomp/snark/MetaInfo.java @@ -61,6 +61,7 @@ public class MetaInfo private final int piece_length; private final byte[] piece_hashes; private final long length; + private final boolean privateTorrent; private Map infoMap; /** @@ -71,7 +72,7 @@ public class MetaInfo * @param lengths null for single-file torrent */ MetaInfo(String announce, String name, String name_utf8, List> files, List lengths, - int piece_length, byte[] piece_hashes, long length) + int piece_length, byte[] piece_hashes, long length, boolean privateTorrent) { this.announce = announce; this.name = name; @@ -82,6 +83,7 @@ public class MetaInfo this.piece_length = piece_length; this.piece_hashes = piece_hashes; this.length = length; + this.privateTorrent = privateTorrent; // TODO if we add a parameter for other keys //if (other != null) { @@ -160,6 +162,10 @@ public class MetaInfo else name_utf8 = null; + // BEP 27 + val = info.get("private"); + privateTorrent = val != null && val.getString().equals("1"); + val = info.get("piece length"); if (val == null) throw new InvalidBEncodingException("Missing piece length number"); @@ -318,6 +324,14 @@ public class MetaInfo return name; } + /** + * Is it a private torrent? + * @since 0.9 + */ + public boolean isPrivate() { + return privateTorrent; + } + /** * Returns a list of lists of file name hierarchies or null if it is * a single name. It has the same size as the list returned by @@ -439,7 +453,7 @@ public class MetaInfo { return new MetaInfo(announce, name, name_utf8, files, lengths, piece_length, - piece_hashes, length); + piece_hashes, length, privateTorrent); } /** @@ -475,6 +489,10 @@ public class MetaInfo info.put("name", name); if (name_utf8 != null) info.put("name.utf-8", name_utf8); + // BEP 27 + if (privateTorrent) + info.put("private", "1"); + info.put("piece length", Integer.valueOf(piece_length)); info.put("pieces", piece_hashes); if (files == null) diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index ffd6f25090..51c1ff4618 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -101,7 +101,8 @@ public class Storage * @param announce may be null * @param listener may be null */ - public Storage(I2PSnarkUtil util, File baseFile, String announce, StorageListener listener) + public Storage(I2PSnarkUtil util, File baseFile, String announce, + boolean privateTorrent, StorageListener listener) throws IOException { _util = util; @@ -157,7 +158,7 @@ public class Storage byte[] piece_hashes = fast_digestCreate(); metainfo = new MetaInfo(announce, baseFile.getName(), null, files, - lengthsList, piece_size, piece_hashes, total); + lengthsList, piece_size, piece_hashes, total, privateTorrent); } 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 4898ddaf4a..dda9be36f6 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -668,7 +668,7 @@ public class I2PSnarkServlet extends Default { try { // This may take a long time to check the storage, but since it already exists, // it shouldn't be THAT bad, so keep it in this thread. - Storage s = new Storage(_manager.util(), baseFile, announceURL, null); + Storage s = new Storage(_manager.util(), baseFile, announceURL, req.getParameter("private") != null, null); s.close(); // close the files... maybe need a way to pass this Storage to addTorrent rather than starting over MetaInfo info = s.getMetaInfo(); File torrentFile = new File(_manager.getDataDir(), s.getBaseName() + ".torrent"); From 295242316b0d00592873b708f88c956699882a90 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 18 Feb 2012 17:58:54 +0000 Subject: [PATCH 02/44] Disable PEX/metadata extensions and open trackers for private torrents Handle announce URLs with parameters correctly --- .../src/org/klomp/snark/ExtensionHandler.java | 14 ++++-- .../java/src/org/klomp/snark/Peer.java | 3 +- .../src/org/klomp/snark/PeerCoordinator.java | 2 + .../java/src/org/klomp/snark/PeerState.java | 7 +++ .../src/org/klomp/snark/TrackerClient.java | 47 ++++++++++++------- 5 files changed, 49 insertions(+), 24 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java index b3770070f4..3d68677646 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java +++ b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java @@ -39,15 +39,19 @@ abstract class ExtensionHandler { /** * @param metasize -1 if unknown + * @param pexAndMetadata advertise these capabilities * @return bencoded outgoing handshake message */ - public static byte[] getHandshake(int metasize) { + public static byte[] getHandshake(int metasize, boolean pexAndMetadata) { Map handshake = new HashMap(); Map m = new HashMap(); - m.put(TYPE_METADATA, Integer.valueOf(ID_METADATA)); - m.put(TYPE_PEX, Integer.valueOf(ID_PEX)); - if (metasize >= 0) - handshake.put("metadata_size", Integer.valueOf(metasize)); + if (pexAndMetadata) { + m.put(TYPE_METADATA, Integer.valueOf(ID_METADATA)); + m.put(TYPE_PEX, Integer.valueOf(ID_PEX)); + if (metasize >= 0) + handshake.put("metadata_size", Integer.valueOf(metasize)); + } + // include the map even if empty so the far-end doesn't NPE handshake.put("m", m); handshake.put("p", Integer.valueOf(6881)); handshake.put("v", "I2PSnark"); diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java index 5489148121..1330365ce8 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java @@ -268,7 +268,8 @@ public class Peer implements Comparable if (_log.shouldLog(Log.DEBUG)) _log.debug("Peer supports extensions, sending reply message"); int metasize = metainfo != null ? metainfo.getInfoBytes().length : -1; - out.sendExtension(0, ExtensionHandler.getHandshake(metasize)); + boolean pexAndMetadata = metainfo == null || !metainfo.isPrivate(); + out.sendExtension(0, ExtensionHandler.getHandshake(metasize, pexAndMetadata)); } if ((options & OPTION_I2P_DHT) != 0 && util.getDHT() != null) { diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index b87c7af3af..c9f70ba251 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -1186,6 +1186,8 @@ public class PeerCoordinator implements PeerListener * @since 0.8.4 */ void sendPeers(Peer peer) { + if (metainfo != null && metainfo.isPrivate()) + return; Map handshake = peer.getHandshakeMap(); if (handshake == null) return; diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index 111ddbbe61..c83a43b191 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -489,6 +489,13 @@ class PeerState implements DataLoader /** @since 0.8.2 */ void extensionMessage(int id, byte[] bs) { + if (metainfo != null && metainfo.isPrivate() && + (id == ExtensionHandler.ID_METADATA || id == ExtensionHandler.ID_PEX)) { + // shouldn't get this since we didn't advertise it but they could send it anyway + if (_log.shouldLog(Log.WARN)) + _log.warn("Private torrent, ignoring ext msg " + id); + return; + } ExtensionHandler.handleMessage(peer, listener, id, bs); // Peer coord will get metadata from MagnetState, // verify, and then call gotMetaInfo() diff --git a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java index 3f7c6b8bd1..2007fb84f2 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java +++ b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java @@ -156,7 +156,7 @@ public class TrackerClient extends I2PAppThread primary = ""; } List tlist = _util.getOpenTrackers(); - if (tlist != null) { + if (tlist != null && !meta.isPrivate()) { for (int i = 0; i < tlist.size(); i++) { String url = (String)tlist.get(i); if (!isValidAnnounce(url)) { @@ -348,7 +348,7 @@ public class TrackerClient extends I2PAppThread } // *** end of trackers loop here // Get peers from PEX - if (left > 0 && coordinator.needPeers() && !stop) { + if (left > 0 && coordinator.needPeers() && (!meta.isPrivate()) && !stop) { Set pids = coordinator.getPEXPeers(); if (!pids.isEmpty()) { _util.debug("Got " + pids.size() + " from PEX", Snark.INFO); @@ -370,7 +370,7 @@ public class TrackerClient extends I2PAppThread // Get peers from DHT // FIXME this needs to be in its own thread - if (_util.getDHT() != null && !stop) { + if (_util.getDHT() != null && (!meta.isPrivate()) && !stop) { int numwant; if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers()) numwant = 1; @@ -444,22 +444,33 @@ public class TrackerClient extends I2PAppThread long downloaded, long left, String event) throws IOException { - // What do we send for left in magnet mode? Can we omit it? - long tleft = left >= 0 ? left : 1; - String s = tr.announce - + "?info_hash=" + infoHash - + "&peer_id=" + peerID - + "&port=" + port - + "&ip=" + _util.getOurIPString() + ".i2p" - + "&uploaded=" + uploaded - + "&downloaded=" + downloaded - + "&left=" + tleft - + "&compact=1" // NOTE: opentracker will return 400 for &compact alone - + ((! event.equals(NO_EVENT)) ? ("&event=" + event) : ""); - if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers()) - s += "&numwant=0"; + StringBuilder buf = new StringBuilder(512); + buf.append(tr.announce); + if (tr.announce.contains("?")) + buf.append('&'); else - s += "&numwant=" + _util.getMaxConnections(); + buf.append('?'); + buf.append("info_hash=").append(infoHash) + .append("&peer_id=").append(peerID) + .append("&port=").append(port) + .append("&ip=" ).append(_util.getOurIPString()).append(".i2p") + .append("&uploaded=").append(uploaded) + .append("&downloaded=").append(downloaded) + .append("&left="); + // What do we send for left in magnet mode? Can we omit it? + if (left >= 0) + buf.append(left); + else + buf.append('1'); + buf.append("&compact=1"); // NOTE: opentracker will return 400 for &compact alone + if (! event.equals(NO_EVENT)) + buf.append("&event=").append(event); + buf.append("&numwant="); + if (left == 0 || event.equals(STOPPED_EVENT) || !coordinator.needPeers()) + buf.append('0'); + else + buf.append(_util.getMaxConnections()); + String s = buf.toString(); _util.debug("Sending TrackerClient request: " + s, Snark.INFO); tr.lastRequestTime = System.currentTimeMillis(); From b47aa34d6a98d97df6029a99a4a696beb48591b6 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 18 Feb 2012 18:50:57 +0000 Subject: [PATCH 03/44] add private option in UI --- apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java | 4 +++- .../java/src/org/klomp/snark/web/I2PSnarkServlet.java | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 0dd3e0731d..a99c8054b1 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -663,7 +663,9 @@ public class SnarkManager implements Snark.CompleteListener { } if (!TrackerClient.isValidAnnounce(info.getAnnounce())) { - if (_util.shouldUseOpenTrackers() && _util.getOpenTrackers() != null) { + if (info.isPrivate()) { + addMessage(_("ERROR - No I2P trackers in private torrent \"{0}\"", info.getName())); + } else if (_util.shouldUseOpenTrackers() && _util.getOpenTrackers() != null) { //addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers and DHT only.", info.getName())); addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers only.", info.getName())); //} else if (_util.getDHT() != null) { 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 77906e9648..1baec88680 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1289,7 +1289,14 @@ public class I2PSnarkServlet extends Default { out.write("\" > " + "\n" + + out.write("\" name=\"foo\" >\n" + + ""); + out.write(_("Private?")); + out.write(" " + + "\n" + ""); } From 3876f74f6ca92cc0f163bfbbecdebed0a8cace0c Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 18 Feb 2012 19:19:42 +0000 Subject: [PATCH 04/44] tooltip --- .../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 1baec88680..b7fbc56e84 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1292,7 +1292,9 @@ public class I2PSnarkServlet extends Default { out.write("\" name=\"foo\" >\n" + ""); out.write(_("Private?")); - out.write(" " + From 3fbd8b8d14f1d460d1b52ea4e1a99260a00383d7 Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 19 Feb 2012 19:52:16 +0000 Subject: [PATCH 05/44] - Fix custom tracker list - Add tracker config form - Remove custom tracker from create form - More icons in buttons --- .../src/org/klomp/snark/SnarkManager.java | 125 ++++++++++----- .../org/klomp/snark/web/I2PSnarkServlet.java | 149 ++++++++++++++++-- .../resources/themes/snark/ubergine/snark.css | 38 +++++ .../resources/themes/snark/vanilla/snark.css | 32 ++++ 4 files changed, 286 insertions(+), 58 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index a99c8054b1..4c46ec6f04 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -8,6 +8,8 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -35,8 +37,6 @@ import net.i2p.util.SecureFileOutputStream; * Manage multiple snarks */ public class SnarkManager implements Snark.CompleteListener { - private static SnarkManager _instance = new SnarkManager(); - public static SnarkManager instance() { return _instance; } /** * Map of (canonical) filename of the .torrent file to Snark instance. @@ -57,6 +57,7 @@ public class SnarkManager implements Snark.CompleteListener { private ConnectionAcceptor _connectionAcceptor; private Thread _monitor; private volatile boolean _running; + private final Map _trackerMap; public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; @@ -89,6 +90,34 @@ public class SnarkManager implements Snark.CompleteListener { public static final int DEFAULT_STARTUP_DELAY = 3; public static final int DEFAULT_REFRESH_DELAY_SECS = 60; + /** + * "name", "announceURL=websiteURL" pairs + * '=' in announceURL must be escaped as , + */ + 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/" +// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/" +// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" +// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" +// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" +// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/" +// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/" + "Postman", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/" + ,"Welterde", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5" + ,"Diftracker", "http://n--XWjHjUPjnMNrSwXA2OYXpMIUL~u4FNXnrt2HtjK3y6j~4SOClyyeKzd0zRPlixxkCe2wfBIYye3bZsaqAD8bd0QMmowxbq91WpjsPfKMiphJbePKXtYAVARiy0cqyvh1d2LyDE-6wkvgaw45hknmS0U-Dg3YTJZbAQRU2SKXgIlAbWCv4R0kDFBLEVpReDiJef3rzAWHiW8yjmJuJilkYjMwlfRjw8xx1nl2s~yhlljk1pl13jGYb0nfawQnuOWeP-ASQWvAAyVgKvZRJE2O43S7iveu9piuv7plXWbt36ef7ndu2GNoNyPOBdpo9KUZ-NOXm4Kgh659YtEibL15dEPAOdxprY0sYUurVw8OIWqrpX7yn08nbi6qHVGqQwTpxH35vkL8qrCbm-ym7oQJQnNmSDrNTyWYRFSq5s5~7DAdFDzqRPW-pX~g0zEivWj5tzkhvG9rVFgFo0bpQX3X0PUAV9Xbyf8u~v8Zbr9K1pCPqBq9XEr4TqaLHw~bfAAAA.i2p/announce.php=http://diftracker.i2p/" +// , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/" +// ,"Exotrack", "http://blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva.b32.i2p/announce.php=http://exotrack.i2p/" + }; + + /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ + public static final String PROP_TRACKERS = "i2psnark.trackers"; + + private static final SnarkManager _instance = new SnarkManager(); + + public static SnarkManager instance() { return _instance; } + private SnarkManager() { _snarks = new ConcurrentHashMap(); _magnets = new ConcurrentHashSet(); @@ -100,6 +129,7 @@ public class SnarkManager implements Snark.CompleteListener { _configFile = new File(CONFIG_FILE); if (!_configFile.isAbsolute()) _configFile = new File(_context.getConfigDir(), CONFIG_FILE); + _trackerMap = Collections.synchronizedMap(new TreeMap(new IgnoreCaseComparator())); loadConfig(null); } @@ -312,6 +342,7 @@ public class SnarkManager implements Snark.CompleteListener { boolean bOT = useOT == null || Boolean.valueOf(useOT).booleanValue(); _util.setUseOpenTrackers(bOT); getDataDir().mkdirs(); + initTrackerMap(); } private int getInt(String prop, int defaultVal) { @@ -1358,57 +1389,59 @@ public class SnarkManager implements Snark.CompleteListener { } /** - * "name", "announceURL=websiteURL" pairs + * Sorted map of name to announceURL=baseURL + * Modifiable, not a copy */ - 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/" -// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/" -// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" -// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" -// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" -// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/" -// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/" - "Postman", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/" - ,"Welterde", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5" - ,"Diftracker", "http://n--XWjHjUPjnMNrSwXA2OYXpMIUL~u4FNXnrt2HtjK3y6j~4SOClyyeKzd0zRPlixxkCe2wfBIYye3bZsaqAD8bd0QMmowxbq91WpjsPfKMiphJbePKXtYAVARiy0cqyvh1d2LyDE-6wkvgaw45hknmS0U-Dg3YTJZbAQRU2SKXgIlAbWCv4R0kDFBLEVpReDiJef3rzAWHiW8yjmJuJilkYjMwlfRjw8xx1nl2s~yhlljk1pl13jGYb0nfawQnuOWeP-ASQWvAAyVgKvZRJE2O43S7iveu9piuv7plXWbt36ef7ndu2GNoNyPOBdpo9KUZ-NOXm4Kgh659YtEibL15dEPAOdxprY0sYUurVw8OIWqrpX7yn08nbi6qHVGqQwTpxH35vkL8qrCbm-ym7oQJQnNmSDrNTyWYRFSq5s5~7DAdFDzqRPW-pX~g0zEivWj5tzkhvG9rVFgFo0bpQX3X0PUAV9Xbyf8u~v8Zbr9K1pCPqBq9XEr4TqaLHw~bfAAAA.i2p/announce.php=http://diftracker.i2p/" -// , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/" -// ,"Exotrack", "http://blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva.b32.i2p/announce.php=http://exotrack.i2p/" - }; - - /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ - public static final String PROP_TRACKERS = "i2psnark.trackers"; - private static Map trackerMap = null; - /** sorted map of name to announceURL=baseURL */ public Map getTrackers() { - if (trackerMap != null) // only do this once, can't be updated while running - return trackerMap; - Map rv = new TreeMap(); + return _trackerMap; + } + + /** @since 0.9 */ + private void initTrackerMap() { String trackers = _config.getProperty(PROP_TRACKERS); if ( (trackers == null) || (trackers.trim().length() <= 0) ) trackers = _context.getProperty(PROP_TRACKERS); + _trackerMap.clear(); if ( (trackers == null) || (trackers.trim().length() <= 0) ) { for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) - rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); + _trackerMap.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); } else { - StringTokenizer tok = new StringTokenizer(trackers, ","); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split <= 0) - continue; - String name = pair.substring(0, split).trim(); - String url = pair.substring(split+1).trim(); + String[] toks = trackers.split(","); + for (int i = 0; i < toks.length; i += 2) { + String name = toks[i].trim().replace(",", ","); + String url = toks[i+1].trim().replace(",", ","); if ( (name.length() > 0) && (url.length() > 0) ) - rv.put(name, url); + _trackerMap.put(name, url); } } - - trackerMap = rv; - return trackerMap; } - + + /** @since 0.9 */ + public void setDefaultTrackerMap() { + _trackerMap.clear(); + for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) { + _trackerMap.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); + } + if (_config.remove(PROP_TRACKERS) != null) { + saveConfig(); + } + } + + /** @since 0.9 */ + public void saveTrackerMap() { + StringBuilder buf = new StringBuilder(2048); + boolean comma = false; + for (Map.Entry e : _trackerMap.entrySet()) { + if (comma) + buf.append(','); + else + comma = true; + buf.append(e.getKey().replace(",", ",")).append(',').append(e.getValue().replace(",", ",")); + } + _config.setProperty(PROP_TRACKERS, buf.toString()); + saveConfig(); + } + private static class TorrentFilenameFilter implements FilenameFilter { private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter(); public static TorrentFilenameFilter instance() { return _filter; } @@ -1428,4 +1461,14 @@ public class SnarkManager implements Snark.CompleteListener { } } } + + /** + * ignore case, current locale + * @since 0.9 + */ + private static class IgnoreCaseComparator implements Comparator { + public int compare(String l, String r) { + return l.toLowerCase().compareTo(r.toLowerCase()); + } + } } 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 b7fbc56e84..80a784b1ff 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -260,6 +260,7 @@ public class I2PSnarkServlet extends Default { if (isConfigure) { out.write("
\n"); writeConfigForm(out, req); + writeTrackerForm(out, req); } else { writeTorrents(out, req); out.write("\n"); @@ -650,14 +651,19 @@ public class I2PSnarkServlet extends Default { _manager.updateConfig(dataDir, filesPublic, autoStart, refreshDel, startupDel, seedPct, eepHost, eepPort, i2cpHost, i2cpPort, i2cpOpts, upLimit, upBW, useOpenTrackers, openTrackers, theme); + } else if ("Save2".equals(action)) { + String taction = req.getParameter("taction"); + if (taction != null) + processTrackerForm(taction, req); } else if ("Create".equals(action)) { String baseData = req.getParameter("baseFile"); if (baseData != null && baseData.trim().length() > 0) { File baseFile = new File(_manager.getDataDir(), baseData); String announceURL = req.getParameter("announceURL"); - String announceURLOther = req.getParameter("announceURLOther"); - if ( (announceURLOther != null) && (announceURLOther.trim().length() > "http://.i2p/announce".length()) ) - announceURL = announceURLOther; + // make the user add a tracker on the config form now + //String announceURLOther = req.getParameter("announceURLOther"); + //if ( (announceURLOther != null) && (announceURLOther.trim().length() > "http://.i2p/announce".length()) ) + // announceURL = announceURLOther; if (announceURL == null || announceURL.length() <= 0) _manager.addMessage(_("Error creating torrent - you must select a tracker")); @@ -713,6 +719,54 @@ public class I2PSnarkServlet extends Default { _manager.addMessage("Unknown POST action: \"" + action + '\"'); } } + + /** @since 0.9 */ + private void processTrackerForm(String action, HttpServletRequest req) { + if (action.equals(_("Delete selected"))) { + boolean changed = false; + Map trackers = _manager.getTrackers(); + Enumeration e = req.getParameterNames(); + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (!(o instanceof String)) + continue; + String k = (String) o; + if (!k.startsWith("delete_")) + continue; + k = k.substring(7); + if (trackers.remove(k) != null) { + _manager.addMessage(_("Removed") + ": " + k); + changed = true; + } + } + if (changed) { + _manager.saveTrackerMap(); + } + } else if (action.equals(_("Add tracker"))) { + String name = req.getParameter("tname"); + String hurl = req.getParameter("thurl"); + String aurl = req.getParameter("taurl"); + if (name != null && hurl != null && aurl != null) { + name = name.trim(); + hurl = hurl.trim(); + aurl = aurl.trim().replace("=", "="); + if (name.length() > 0 && hurl.startsWith("http://") && aurl.startsWith("http://")) { + Map trackers = _manager.getTrackers(); + trackers.put(name, aurl + '=' + hurl); + _manager.saveTrackerMap(); + } else { + _manager.addMessage(_("Enter valid tracker name and URLs")); + } + } else { + _manager.addMessage(_("Enter valid tracker name and URLs")); + } + } else if (action.equals(_("Restore defaults"))) { + _manager.setDefaultTrackerMap(); + _manager.addMessage(_("Restored default trackers")); + } else { + _manager.addMessage("Unknown POST action: \"" + action + '\"'); + } + } private static final String iopts[] = {"inbound.length", "inbound.quantity", "outbound.length", "outbound.quantity" }; @@ -1222,7 +1276,7 @@ public class I2PSnarkServlet extends Default { out.write("\"> \n"); // not supporting from file at the moment, since the file name passed isn't always absolute (so it may not resolve) //out.write("From file:
"); - out.write("
\n"); out.write(" "); @@ -1269,25 +1323,25 @@ public class I2PSnarkServlet extends Default { //out.write(_("Open trackers and DHT only")); out.write(_("Open trackers only")); out.write("\n"); - Map trackers = _manager.getTrackers(); - for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { - Map.Entry entry = (Map.Entry)iter.next(); - String name = (String)entry.getKey(); - String announceURL = (String)entry.getValue(); + Map trackers = _manager.getTrackers(); + for (Map.Entry entry : trackers.entrySet()) { + String name = entry.getKey(); + String announceURL = entry.getValue(); int e = announceURL.indexOf('='); if (e > 0) - announceURL = announceURL.substring(0, e); + announceURL = announceURL.substring(0, e).replace("=", "="); if (announceURL.equals(_lastAnnounceURL)) announceURL += "\" selected=\"selected"; out.write("\t\n"); } out.write("\n"); - out.write(_("or")); - out.write("  " + - " " + + out.write(" \n" + ""); @@ -1482,6 +1536,57 @@ public class I2PSnarkServlet extends Default { ""); } + /** @since 0.9 */ + private void writeTrackerForm(PrintWriter out, HttpServletRequest req) throws IOException { + StringBuilder buf = new StringBuilder(1024); + buf.append("
\n" + + "
\n" + + "\n" + + "\n" + + "" + + "\"\" "); + buf.append(_("Trackers")); + buf.append("
\n" + + "\n"); + Map trackers = _manager.getTrackers(); + for (Map.Entry entry : trackers.entrySet()) { + String name = entry.getKey(); + String announceURL = entry.getValue(); + int e = announceURL.indexOf('='); + if (e <= 0) + continue; + String homeURL = announceURL.substring(e + 1); + announceURL = announceURL.substring(0, e).replace("=", "="); + buf.append("\n"); + } + buf.append("" + + "" + + "" + + "\n" + + "
") + //.append(_("Remove")) + .append("") + .append(_("Name")) + .append("") + .append(_("Website URL")) + .append("") + .append(_("Announce URL")) + .append("
" + + "").append(name) + .append("").append(urlify(homeURL, 35)) + .append("").append(urlify(announceURL, 35)) + .append("
") + .append(_("Add")).append(":
\n" + + "\n" + + "\n" + + // "\n" + + "\n" + + "\n" + + "
\n"); + out.write(buf.toString()); + } + private void writeConfigLink(PrintWriter out) throws IOException { out.write("
\n" + "" + @@ -1631,10 +1736,20 @@ public class I2PSnarkServlet extends Default { /** @since 0.7.14 */ private static String urlify(String s) { + return urlify(s, 100); + } + + /** @since 0.9 */ + private static String urlify(String s, int max) { StringBuilder buf = new StringBuilder(256); // browsers seem to work without doing this but let's be strict String link = urlEncode(s); - buf.append("").append(link).append(""); + String display; + if (s.length() <= max) + display = link; + else + display = urlEncode(s.substring(0, max)) + "…"; + buf.append("").append(display).append(""); return buf.toString(); } diff --git a/installer/resources/themes/snark/ubergine/snark.css b/installer/resources/themes/snark/ubergine/snark.css index 01c1632e34..ec7583decf 100644 --- a/installer/resources/themes/snark/ubergine/snark.css +++ b/installer/resources/themes/snark/ubergine/snark.css @@ -525,12 +525,50 @@ input[type=radio] { vertical-align: bottom; } +input.default { width: 1px; height: 1px; visibility: hidden; } + input.accept { background: #989 url('../../console/images/accept.png') no-repeat 2px center; padding: 2px 3px 2px 20px !important; min-height: 22px; } +input.add { + background: #989 url('../../console/images/add.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.create { + background: #989 url('images/create.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.cancel { + background: #989 url('../../console/images/cancel.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.create { + background: #989 url('images/create.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.delete { + background: #989 url('../../console/images/delete.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.reload { + background: #989 url('../../console/images/arrow_refresh.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + select { background: #333; background: url('/themes/snark/ubergine/images/graytile.png') !important; diff --git a/installer/resources/themes/snark/vanilla/snark.css b/installer/resources/themes/snark/vanilla/snark.css index b0c0c1de5d..de8cba80fb 100644 --- a/installer/resources/themes/snark/vanilla/snark.css +++ b/installer/resources/themes/snark/vanilla/snark.css @@ -549,12 +549,44 @@ input[type=radio] { vertical-align: bottom; } +input.default { width: 1px; height: 1px; visibility: hidden; } + input.accept { background: #f3efc7 url('../../console/images/accept.png') no-repeat 2px center; padding: 2px 3px 2px 20px !important; min-height: 22px; } +input.add { + background: #f3efc7 url('../../console/images/add.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.cancel { + background: #f3efc7 url('../../console/images/cancel.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.create { + background: #f3efc7 url('images/create.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.delete { + background: #f3efc7 url('../../console/images/delete.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + +input.reload { + background: #f3efc7 url('../../console/images/arrow_refresh.png') no-repeat 2px center; + padding: 2px 3px 2px 20px !important; + min-height: 22px; +} + select { background: #fff; /* background: url('/themes/snark/ubergine/images/graytile.png') !important;*/ From 13731e7b35cc0637c375167b3815aa7acfe3499e Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 19 Feb 2012 20:57:44 +0000 Subject: [PATCH 06/44] add b64 hash --- apps/susidns/src/java/src/i2p/susi/dns/AddressBean.java | 9 +++++++++ apps/susidns/src/jsp/details.jsp | 3 +++ 2 files changed, 12 insertions(+) diff --git a/apps/susidns/src/java/src/i2p/susi/dns/AddressBean.java b/apps/susidns/src/java/src/i2p/susi/dns/AddressBean.java index 6f34af3e5b..9c1c858631 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/AddressBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/AddressBean.java @@ -170,6 +170,15 @@ public class AddressBean return Base32.encode(hash) + ".b32.i2p"; } + /** @since 0.9 */ + public String getB64() + { + byte[] dest = Base64.decode(destination); + if (dest == null) + return ""; + return I2PAppContext.getGlobalContext().sha().calculateHash(dest).toBase64(); + } + /** @since 0.8.7 */ public void setProperties(Properties p) { props = p; diff --git a/apps/susidns/src/jsp/details.jsp b/apps/susidns/src/jsp/details.jsp index f9769ecac1..3d59c7dc1f 100644 --- a/apps/susidns/src/jsp/details.jsp +++ b/apps/susidns/src/jsp/details.jsp @@ -94,6 +94,9 @@ <%=intl._("Base 32 Address")%> <%=b32%> +<%=intl._("Base 64 Hash")%> +<%=addr.getB64()%> + <%=intl._("Address Helper")%> <%=intl._("link")%> From 667bd466439b3853e7bde28c078ff0d4a96191d9 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 22 Feb 2012 15:41:04 +0000 Subject: [PATCH 07/44] hide stat log config unless already enabled --- .../net/i2p/router/web/ConfigStatsHelper.java | 12 ++++- apps/routerconsole/jsp/configstats.jsp | 53 +++++++++++++++---- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java index 254a20728d..61d4969330 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java @@ -59,8 +59,16 @@ public class ConfigStatsHelper extends HelperBase { _filters.add(tok.nextToken().trim()); } - public ConfigStatsHelper() {} - + /** + * Just hide for everybody unless already set. + * To enable set advanced config stat.logFilters=foo before starting... + * it has to be set at startup anyway for logging to be enabled at all + * @since 0.9 + */ + public boolean shouldShowLog() { + return !_filters.isEmpty(); + } + public String getFilename() { return _context.statManager().getStatFile(); } /** diff --git a/apps/routerconsole/jsp/configstats.jsp b/apps/routerconsole/jsp/configstats.jsp index 7e548a1136..94cf968331 100644 --- a/apps/routerconsole/jsp/configstats.jsp +++ b/apps/routerconsole/jsp/configstats.jsp @@ -78,8 +78,19 @@ function toggleAll(category) checked="true" <% } %> > (<%=intl._("change requires restart to take effect")%>)
- <%=intl._("Stat file")%>:
-<%=intl._("Filter")%>: (<%=intl._("toggle all")%>)

+<% + + // stats.log for devs only and grows without bounds, not recommended + boolean shouldShowLog = statshelper.shouldShowLog(); + if (shouldShowLog) { + +%><%=intl._("Stat file")%>:
+Warning - Log with care, stat file grows without limit.
+<% + + } // shouldShowLog + +%><%=intl._("Filter")%>: (<%=intl._("toggle all")%>)

<% while (statshelper.hasMoreStats()) { @@ -90,27 +101,51 @@ function toggleAll(category) (<%=intl._("toggle all")%>) - - +<% + + if (shouldShowLog) { + +%> +<% + + } // shouldShowLog + +%> <% } // end iterating over required groups for the current stat %> - +<% + + if (shouldShowLog) { + +%> - <% - } // end iterating over all stats %> - + } // end iterating over all stats + + if (shouldShowLog) { + +%> - From a288fc52e0801bacafe05fc63bd627ca97ea7629 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 23 Feb 2012 15:40:31 +0000 Subject: [PATCH 08/44] Move icon URL from _icons to .icons --- apps/i2psnark/{_icons => icons}/application.png | Bin apps/i2psnark/{_icons => icons}/cancel.png | Bin apps/i2psnark/{_icons => icons}/cd.png | Bin apps/i2psnark/{_icons => icons}/clock.png | Bin apps/i2psnark/{_icons => icons}/clock_red.png | Bin apps/i2psnark/{_icons => icons}/compress.png | Bin apps/i2psnark/{_icons => icons}/film.png | Bin apps/i2psnark/{_icons => icons}/folder.png | Bin apps/i2psnark/{_icons => icons}/html.png | Bin apps/i2psnark/{_icons => icons}/magnet.png | Bin apps/i2psnark/{_icons => icons}/music.png | Bin apps/i2psnark/{_icons => icons}/package.png | Bin apps/i2psnark/{_icons => icons}/page.png | Bin apps/i2psnark/{_icons => icons}/page_white.png | Bin .../{_icons => icons}/page_white_acrobat.png | Bin apps/i2psnark/{_icons => icons}/photo.png | Bin apps/i2psnark/{_icons => icons}/plugin.png | Bin apps/i2psnark/{_icons => icons}/tick.png | Bin apps/i2psnark/java/build.xml | 8 ++++++-- .../src/org/klomp/snark/web/I2PSnarkServlet.java | 6 +++--- 20 files changed, 9 insertions(+), 5 deletions(-) rename apps/i2psnark/{_icons => icons}/application.png (100%) rename apps/i2psnark/{_icons => icons}/cancel.png (100%) rename apps/i2psnark/{_icons => icons}/cd.png (100%) rename apps/i2psnark/{_icons => icons}/clock.png (100%) rename apps/i2psnark/{_icons => icons}/clock_red.png (100%) rename apps/i2psnark/{_icons => icons}/compress.png (100%) rename apps/i2psnark/{_icons => icons}/film.png (100%) rename apps/i2psnark/{_icons => icons}/folder.png (100%) rename apps/i2psnark/{_icons => icons}/html.png (100%) rename apps/i2psnark/{_icons => icons}/magnet.png (100%) rename apps/i2psnark/{_icons => icons}/music.png (100%) rename apps/i2psnark/{_icons => icons}/package.png (100%) rename apps/i2psnark/{_icons => icons}/page.png (100%) rename apps/i2psnark/{_icons => icons}/page_white.png (100%) rename apps/i2psnark/{_icons => icons}/page_white_acrobat.png (100%) rename apps/i2psnark/{_icons => icons}/photo.png (100%) rename apps/i2psnark/{_icons => icons}/plugin.png (100%) rename apps/i2psnark/{_icons => icons}/tick.png (100%) diff --git a/apps/i2psnark/_icons/application.png b/apps/i2psnark/icons/application.png similarity index 100% rename from apps/i2psnark/_icons/application.png rename to apps/i2psnark/icons/application.png diff --git a/apps/i2psnark/_icons/cancel.png b/apps/i2psnark/icons/cancel.png similarity index 100% rename from apps/i2psnark/_icons/cancel.png rename to apps/i2psnark/icons/cancel.png diff --git a/apps/i2psnark/_icons/cd.png b/apps/i2psnark/icons/cd.png similarity index 100% rename from apps/i2psnark/_icons/cd.png rename to apps/i2psnark/icons/cd.png diff --git a/apps/i2psnark/_icons/clock.png b/apps/i2psnark/icons/clock.png similarity index 100% rename from apps/i2psnark/_icons/clock.png rename to apps/i2psnark/icons/clock.png diff --git a/apps/i2psnark/_icons/clock_red.png b/apps/i2psnark/icons/clock_red.png similarity index 100% rename from apps/i2psnark/_icons/clock_red.png rename to apps/i2psnark/icons/clock_red.png diff --git a/apps/i2psnark/_icons/compress.png b/apps/i2psnark/icons/compress.png similarity index 100% rename from apps/i2psnark/_icons/compress.png rename to apps/i2psnark/icons/compress.png diff --git a/apps/i2psnark/_icons/film.png b/apps/i2psnark/icons/film.png similarity index 100% rename from apps/i2psnark/_icons/film.png rename to apps/i2psnark/icons/film.png diff --git a/apps/i2psnark/_icons/folder.png b/apps/i2psnark/icons/folder.png similarity index 100% rename from apps/i2psnark/_icons/folder.png rename to apps/i2psnark/icons/folder.png diff --git a/apps/i2psnark/_icons/html.png b/apps/i2psnark/icons/html.png similarity index 100% rename from apps/i2psnark/_icons/html.png rename to apps/i2psnark/icons/html.png diff --git a/apps/i2psnark/_icons/magnet.png b/apps/i2psnark/icons/magnet.png similarity index 100% rename from apps/i2psnark/_icons/magnet.png rename to apps/i2psnark/icons/magnet.png diff --git a/apps/i2psnark/_icons/music.png b/apps/i2psnark/icons/music.png similarity index 100% rename from apps/i2psnark/_icons/music.png rename to apps/i2psnark/icons/music.png diff --git a/apps/i2psnark/_icons/package.png b/apps/i2psnark/icons/package.png similarity index 100% rename from apps/i2psnark/_icons/package.png rename to apps/i2psnark/icons/package.png diff --git a/apps/i2psnark/_icons/page.png b/apps/i2psnark/icons/page.png similarity index 100% rename from apps/i2psnark/_icons/page.png rename to apps/i2psnark/icons/page.png diff --git a/apps/i2psnark/_icons/page_white.png b/apps/i2psnark/icons/page_white.png similarity index 100% rename from apps/i2psnark/_icons/page_white.png rename to apps/i2psnark/icons/page_white.png diff --git a/apps/i2psnark/_icons/page_white_acrobat.png b/apps/i2psnark/icons/page_white_acrobat.png similarity index 100% rename from apps/i2psnark/_icons/page_white_acrobat.png rename to apps/i2psnark/icons/page_white_acrobat.png diff --git a/apps/i2psnark/_icons/photo.png b/apps/i2psnark/icons/photo.png similarity index 100% rename from apps/i2psnark/_icons/photo.png rename to apps/i2psnark/icons/photo.png diff --git a/apps/i2psnark/_icons/plugin.png b/apps/i2psnark/icons/plugin.png similarity index 100% rename from apps/i2psnark/_icons/plugin.png rename to apps/i2psnark/icons/plugin.png diff --git a/apps/i2psnark/_icons/tick.png b/apps/i2psnark/icons/tick.png similarity index 100% rename from apps/i2psnark/_icons/tick.png rename to apps/i2psnark/icons/tick.png diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index c5a3b106fd..bd8e25d140 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -95,9 +95,13 @@ - + + + + + @@ -109,7 +113,7 @@ - + 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 80a784b1ff..beebc226ae 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -102,7 +102,7 @@ public class I2PSnarkServlet extends Default { protected Resource getResource(String pathInContext) throws IOException { if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") || - pathInContext.equals("/index.html") || pathInContext.startsWith("/_icons/")) + pathInContext.equals("/index.html") || pathInContext.startsWith("/.icons/")) return super.getResource(pathInContext); // files in the i2psnark/ directory return _resourceBase.addPath(pathInContext); @@ -2115,12 +2115,12 @@ public class I2PSnarkServlet extends Default { /** @since 0.7.14 */ private static String toImg(String icon) { - return "\"\""; + return "\"\""; } /** @since 0.8.2 */ private static String toImg(String icon, String altText) { - return "\"""; + return "\"""; } /** @since 0.8.1 */ From 141ad676507f9171adb9041d032a247d878e650a Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 23 Feb 2012 17:41:06 +0000 Subject: [PATCH 09/44] ajaxify the refresh --- apps/i2psnark/java/build.xml | 6 +- .../org/klomp/snark/web/I2PSnarkServlet.java | 67 +++++++++++++------ apps/i2psnark/js/i2psnark.js | 37 ++++++++++ 3 files changed, 89 insertions(+), 21 deletions(-) create mode 100644 apps/i2psnark/js/i2psnark.js diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index bd8e25d140..bded42a27f 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -98,10 +98,14 @@ + + + + @@ -113,7 +117,7 @@ - + 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 beebc226ae..e5db6f6cb7 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -102,7 +102,8 @@ public class I2PSnarkServlet extends Default { protected Resource getResource(String pathInContext) throws IOException { if (pathInContext == null || pathInContext.equals("/") || pathInContext.equals("/index.jsp") || - pathInContext.equals("/index.html") || pathInContext.startsWith("/.icons/")) + pathInContext.equals("/index.html") || pathInContext.startsWith("/.icons/") || + pathInContext.startsWith("/.js/") || pathInContext.startsWith("/.ajax/")) return super.getResource(pathInContext); // files in the i2psnark/ directory return _resourceBase.addPath(pathInContext); @@ -151,6 +152,17 @@ public class I2PSnarkServlet extends Default { _imgPath = _themePath + "images/"; // this is the part after /i2psnark String path = req.getServletPath(); + + // AJAX for mainsection + if ("/.ajax/xhr1.html".equals(path)) { + resp.setCharacterEncoding("UTF-8"); + resp.setContentType("text/html; charset=UTF-8"); + PrintWriter out = resp.getWriter(); + writeMessages(out); + writeTorrents(out, req); + return; + } + boolean isConfigure = "/configure".equals(path); // index.jsp doesn't work, it is grabbed by the war handler before here if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html") || path.equals("/_post") || isConfigure)) { @@ -208,13 +220,18 @@ public class I2PSnarkServlet extends Default { out.write("\n"); // we want it to go to the base URI so we don't refresh with some funky action= value + int delay = 0; if (!isConfigure) { - int delay = _manager.getRefreshDelaySeconds(); + delay = _manager.getRefreshDelaySeconds(); if (delay > 0) - out.write("\n"); + //out.write("\n"); + out.write("\n"); } - out.write(HEADER_A + _themePath + HEADER_B); - out.write(""); + out.write(HEADER_A + _themePath + HEADER_B + "\n"); + if (isConfigure || delay <= 0) + out.write(""); + else + out.write(""); out.write("
"); if (isConfigure) { out.write("
<%=intl._("Log")%><%=intl._("Graph")%><%=intl._("Log")%><%=intl._("Graph")%>
+
checked="true" <% } %> > +<% + + } // shouldShowLog + +%> <% if (statshelper.getCurrentCanBeGraphed()) { %> checked="true" <% } %> ><% } %> <%=statshelper.getCurrentStatName()%>:
<%=statshelper.getCurrentStatDescription()%>
<%=intl._("Advanced filter")%>:
+<% + + } // shouldShowLog + +%>
" > " >
" + From 6ebd1f121aab0a300e9bdf73a3096511603d2aed Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 26 Feb 2012 23:05:21 +0000 Subject: [PATCH 17/44] installer build fixups --- build.xml | 56 +++++++++++++++---------------------- installer/i2pstandalone.xml | 2 +- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/build.xml b/build.xml index a0ffe8ab54..dcfa94b675 100644 --- a/build.xml +++ b/build.xml @@ -206,6 +206,7 @@ + @@ -234,6 +235,7 @@ classname="net.sf.launch4j.ant.Launch4jTask" classpath="${basedir}/installer/lib/launch4j/launch4j.jar:${basedir}/installer/lib/launch4j/lib/xstream.jar" /> + @@ -572,7 +574,6 @@ - @@ -754,7 +755,7 @@ - + @@ -1169,43 +1170,31 @@ + - - - - - - + + - - - - - + + - - - - - + + - - + - - - + @@ -1218,28 +1207,25 @@ - - + + - + - + - + - - + @@ -1267,8 +1253,10 @@ - - + + + + diff --git a/installer/i2pstandalone.xml b/installer/i2pstandalone.xml index 9a6f0a6595..60ba8163bb 100644 --- a/installer/i2pstandalone.xml +++ b/installer/i2pstandalone.xml @@ -1,7 +1,7 @@ 0 ../build/launchi2p.jar - ../i2p.exe + ../build/i2p.exe I2P . false From bda3fbbe63174cfdfc578d7982bc265f6c5513f6 Mon Sep 17 00:00:00 2001 From: zzz Date: Mon, 27 Feb 2012 21:15:56 +0000 Subject: [PATCH 18/44] add icon to installer exe --- installer/i2pinstaller.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/installer/i2pinstaller.xml b/installer/i2pinstaller.xml index fd46517beb..4751a85650 100644 --- a/installer/i2pinstaller.xml +++ b/installer/i2pinstaller.xml @@ -5,7 +5,7 @@ I2P Installer . false - + resources/console.ico 1.5.0 From d0dca206f716a1cb0511226a35fe1296a61e505f Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 28 Feb 2012 13:20:34 +0000 Subject: [PATCH 19/44] release script tweaks --- build.xml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/build.xml b/build.xml index dcfa94b675..69e7e9414f 100644 --- a/build.xml +++ b/build.xml @@ -1371,8 +1371,9 @@ - - + + + @@ -1482,6 +1483,17 @@ + + + + + + + + + + + From cf5d7d2f08bd7f16992d192b39a1633ed7752970 Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 28 Feb 2012 13:28:25 +0000 Subject: [PATCH 20/44] remove dtg from updater --- build.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.xml b/build.xml index 69e7e9414f..fa9746e537 100644 --- a/build.xml +++ b/build.xml @@ -1017,7 +1017,9 @@ + From 4f6ed70044d9b7b8cbb85f5c7deaab47822eeb6e Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 28 Feb 2012 14:35:32 +0000 Subject: [PATCH 21/44] remove static logs --- core/java/src/net/i2p/data/Base32.java | 6 +++--- core/java/src/net/i2p/data/Base64.java | 4 ++-- core/java/src/net/i2p/data/DataStructureImpl.java | 10 ++++++---- core/java/src/net/i2p/data/Payload.java | 10 +++++----- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/core/java/src/net/i2p/data/Base32.java b/core/java/src/net/i2p/data/Base32.java index fd6f81a02d..d3d438d62e 100644 --- a/core/java/src/net/i2p/data/Base32.java +++ b/core/java/src/net/i2p/data/Base32.java @@ -29,7 +29,7 @@ import net.i2p.util.Log; */ public class Base32 { - private final static Log _log = new Log(Base32.class); + //private final static Log _log = new Log(Base32.class); /** The 32 valid Base32 values. */ private final static char[] ALPHABET = {'a', 'b', 'c', 'd', @@ -248,12 +248,12 @@ public class Base32 { outBuff[outBuffPosn] = next; usedbits -= 3; } else if (next != 0) { - _log.warn("Extra data at the end: " + next + "(decimal)"); + //_log.warn("Extra data at the end: " + next + "(decimal)"); return null; } } } else { - _log.warn("Bad Base32 input character at " + i + ": " + source[i] + "(decimal)"); + //_log.warn("Bad Base32 input character at " + i + ": " + source[i] + "(decimal)"); return null; } } diff --git a/core/java/src/net/i2p/data/Base64.java b/core/java/src/net/i2p/data/Base64.java index 6f5fc34a57..9adb3e202e 100644 --- a/core/java/src/net/i2p/data/Base64.java +++ b/core/java/src/net/i2p/data/Base64.java @@ -41,7 +41,7 @@ import net.i2p.util.Log; */ public class Base64 { - private final static Log _log = new Log(Base64.class); + //private final static Log _log = new Log(Base64.class); /** * @param source if null will return "" @@ -750,7 +750,7 @@ public class Base64 { } // end if: white space, equals sign or better else { - _log.warn("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); + //_log.warn("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)"); return null; } // end else: } // each input character diff --git a/core/java/src/net/i2p/data/DataStructureImpl.java b/core/java/src/net/i2p/data/DataStructureImpl.java index b4b43eb57a..1ca043672e 100644 --- a/core/java/src/net/i2p/data/DataStructureImpl.java +++ b/core/java/src/net/i2p/data/DataStructureImpl.java @@ -14,6 +14,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import net.i2p.I2PAppContext; import net.i2p.crypto.SHA256Generator; import net.i2p.util.Log; @@ -23,7 +24,6 @@ import net.i2p.util.Log; * @author jrandom */ public abstract class DataStructureImpl implements DataStructure { - private final static Log _log = new Log(DataStructureImpl.class); public String toBase64() { byte data[] = toByteArray(); @@ -48,10 +48,12 @@ public abstract class DataStructureImpl implements DataStructure { writeBytes(baos); return baos.toByteArray(); } catch (IOException ioe) { - _log.error("Error writing out the byte array", ioe); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass()); + log.error("Error writing out the byte array", ioe); return null; } catch (DataFormatException dfe) { - _log.error("Error writing out the byte array", dfe); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(getClass()); + log.error("Error writing out the byte array", dfe); return null; } } @@ -73,4 +75,4 @@ public abstract class DataStructureImpl implements DataStructure { protected int read(InputStream in, byte target[]) throws IOException { return DataHelper.read(in, target); } -} \ No newline at end of file +} diff --git a/core/java/src/net/i2p/data/Payload.java b/core/java/src/net/i2p/data/Payload.java index bdaac7d4c5..453fe80773 100644 --- a/core/java/src/net/i2p/data/Payload.java +++ b/core/java/src/net/i2p/data/Payload.java @@ -26,7 +26,7 @@ import net.i2p.util.Log; * @author jrandom */ public class Payload extends DataStructureImpl { - private final static Log _log = new Log(Payload.class); + //private final static Log _log = new Log(Payload.class); private byte[] _encryptedData; private byte[] _unencryptedData; @@ -82,16 +82,16 @@ public class Payload extends DataStructureImpl { _encryptedData = new byte[size]; int read = read(in, _encryptedData); if (read != size) throw new DataFormatException("Incorrect number of bytes read in the payload structure"); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("read payload: " + read + " bytes"); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("read payload: " + read + " bytes"); } public void writeBytes(OutputStream out) throws DataFormatException, IOException { if (_encryptedData == null) throw new DataFormatException("Not yet encrypted. Please set the encrypted data"); DataHelper.writeLong(out, 4, _encryptedData.length); out.write(_encryptedData); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("wrote payload: " + _encryptedData.length); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("wrote payload: " + _encryptedData.length); } /** From d6d8c0d119295bb6e29cf1a680d3ef4fda48ad7a Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 28 Feb 2012 14:50:39 +0000 Subject: [PATCH 22/44] remove static logs --- core/java/src/net/i2p/util/Log.java | 2 +- core/java/src/net/i2p/util/SimpleTimer2.java | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/java/src/net/i2p/util/Log.java b/core/java/src/net/i2p/util/Log.java index 0a03e19b5e..538e3986b9 100644 --- a/core/java/src/net/i2p/util/Log.java +++ b/core/java/src/net/i2p/util/Log.java @@ -16,7 +16,7 @@ import net.i2p.I2PAppContext; /** * Wrapper class for whatever logging system I2P uses. This class should be * instantiated and kept as a variable for each class it is used by, ala: - * private final static Log _log = new Log(MyClassName.class); + * private final Log _log = context.logManager().getLog(MyClassName.class); * * If there is anything in here that doesn't make sense, turn off your computer * and go fly a kite. diff --git a/core/java/src/net/i2p/util/SimpleTimer2.java b/core/java/src/net/i2p/util/SimpleTimer2.java index ab568d6446..8e2aee8a74 100644 --- a/core/java/src/net/i2p/util/SimpleTimer2.java +++ b/core/java/src/net/i2p/util/SimpleTimer2.java @@ -31,7 +31,6 @@ public class SimpleTimer2 { private static final int MIN_THREADS = 2; private static final int MAX_THREADS = 4; private final I2PAppContext _context; - private static Log _log; // static so TimedEvent can use it private final ScheduledThreadPoolExecutor _executor; private final String _name; private int _count; @@ -40,7 +39,6 @@ public class SimpleTimer2 { protected SimpleTimer2() { this("SimpleTimer2"); } protected SimpleTimer2(String name) { _context = I2PAppContext.getGlobalContext(); - _log = _context.logManager().getLog(SimpleTimer2.class); _name = name; _count = 0; long maxMemory = Runtime.getRuntime().maxMemory(); @@ -79,8 +77,10 @@ public class SimpleTimer2 { @Override protected void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); - if (t != null) // shoudn't happen, caught in RunnableEvent.run() - _log.log(Log.CRIT, "wtf, event borked: " + r, t); + if (t != null) { // shoudn't happen, caught in RunnableEvent.run() + Log log = I2PAppContext.getGlobalContext().logManager().getLog(SimpleTimer2.class); + log.log(Log.CRIT, "wtf, event borked: " + r, t); + } } } @@ -126,6 +126,7 @@ public class SimpleTimer2 { * */ public static abstract class TimedEvent implements Runnable { + private final Log _log; private SimpleTimer2 _pool; private int _fuzz; protected static final int DEFAULT_FUZZ = 3; @@ -136,7 +137,9 @@ public class SimpleTimer2 { public TimedEvent(SimpleTimer2 pool) { _pool = pool; _fuzz = DEFAULT_FUZZ; + _log = I2PAppContext.getGlobalContext().logManager().getLog(SimpleTimer2.class); } + /** automatically schedules, don't use this one if you have other things to do first */ public TimedEvent(SimpleTimer2 pool, long timeoutMs) { this(pool); From 17f7264863d15ecee014731996237eb3784a8523 Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 28 Feb 2012 15:26:31 +0000 Subject: [PATCH 23/44] remove unused counters and methods --- core/java/src/net/i2p/data/Lease.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/core/java/src/net/i2p/data/Lease.java b/core/java/src/net/i2p/data/Lease.java index 283e2aa7c2..d6c97f1502 100644 --- a/core/java/src/net/i2p/data/Lease.java +++ b/core/java/src/net/i2p/data/Lease.java @@ -26,8 +26,8 @@ public class Lease extends DataStructureImpl { private Hash _gateway; private TunnelId _tunnelId; private Date _end; - private int _numSuccess; - private int _numFailure; + //private int _numSuccess; + //private int _numFailure; public Lease() { } @@ -74,14 +74,18 @@ public class Lease extends DataStructureImpl { * * @deprecated unused */ +/**** public int getNumSuccess() { return _numSuccess; } +****/ /** @deprecated unused */ +/**** public void setNumSuccess(int num) { _numSuccess = num; } +****/ /** * Transient attribute of the lease, used to note how many times messages sent @@ -89,14 +93,18 @@ public class Lease extends DataStructureImpl { * * @deprecated unused */ +/**** public int getNumFailure() { return _numFailure; } +****/ /** @deprecated unused */ +/**** public void setNumFailure(int num) { _numFailure = num; } +****/ /** has this lease already expired? */ public boolean isExpired() { From ede1b1954c2a8e30252595c69e97155cdf350b44 Mon Sep 17 00:00:00 2001 From: zzz Date: Tue, 28 Feb 2012 15:58:02 +0000 Subject: [PATCH 24/44] remove static logs --- .../i2p/router/client/ClientManagerFacadeImpl.java | 5 +++-- .../i2p/router/networkdb/kademlia/LocalHash.java | 6 +++++- .../router/networkdb/kademlia/MessageWrapper.java | 14 +++++++------- .../net/i2p/router/transport/ntcp/NTCPAddress.java | 9 +++++---- .../net/i2p/router/transport/udp/UDPPacket.java | 13 ++++++------- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java index 94e2c0cf35..022326cb6d 100644 --- a/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java +++ b/router/java/src/net/i2p/router/client/ClientManagerFacadeImpl.java @@ -36,7 +36,7 @@ import net.i2p.util.Log; * @author jrandom */ public class ClientManagerFacadeImpl extends ClientManagerFacade implements InternalClientManager { - private final static Log _log = new Log(ClientManagerFacadeImpl.class); + private final Log _log; private ClientManager _manager; private RouterContext _context; /** note that this is different than the property the client side uses, i2cp.tcp.port */ @@ -48,7 +48,8 @@ public class ClientManagerFacadeImpl extends ClientManagerFacade implements Inte public ClientManagerFacadeImpl(RouterContext context) { _context = context; - _log.debug("Client manager facade created"); + _log = _context.logManager().getLog(ClientManagerFacadeImpl.class); + //_log.debug("Client manager facade created"); } public void startup() { diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java b/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java index ebf787ad09..53a28019c8 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/LocalHash.java @@ -27,7 +27,7 @@ import net.i2p.util.Log; * @author moved from Hash.java by zzz */ class LocalHash extends Hash { - private final static Log _log = new Log(LocalHash.class); + //private final static Log _log = new Log(LocalHash.class); private /* FIXME final FIXME */ Map _xorCache; private static final int MAX_CACHED_XOR = 1024; @@ -86,6 +86,7 @@ class LocalHash extends Hash { _xorCache.put(key, distance); cached = _xorCache.size(); } + /**** if (_log.shouldLog(Log.DEBUG)) { // explicit buffer, since the compiler can't guess how long it'll be StringBuilder buf = new StringBuilder(128); @@ -94,7 +95,9 @@ class LocalHash extends Hash { buf.append(DataHelper.toHexString(key.getData())); _log.debug(buf.toString(), new Exception()); } + ****/ } else { + /**** if (_log.shouldLog(Log.DEBUG)) { // explicit buffer, since the compiler can't guess how long it'll be StringBuilder buf = new StringBuilder(128); @@ -103,6 +106,7 @@ class LocalHash extends Hash { buf.append(DataHelper.toHexString(key.getData())); _log.debug(buf.toString()); } + ****/ } return distance; } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java index b53269e521..d855079164 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/MessageWrapper.java @@ -27,7 +27,7 @@ import net.i2p.util.Log; */ class MessageWrapper { - private static final Log _log = RouterContext.getGlobalContext().logManager().getLog(MessageWrapper.class); + //private static final Log _log = RouterContext.getGlobalContext().logManager().getLog(MessageWrapper.class); private static final int NETDB_TAGS_TO_DELIVER = 6; private static final int NETDB_LOW_THRESHOLD = 3; @@ -71,8 +71,8 @@ class MessageWrapper { PublicKey sentTo = to.getIdentity().getPublicKey(); if (!sentTags.isEmpty()) tsh = skm.tagsDelivered(sentTo, sentKey, sentTags); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Sent to: " + to.getIdentity().getHash() + " with key: " + sentKey + " and tags: " + sentTags.size()); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Sent to: " + to.getIdentity().getHash() + " with key: " + sentKey + " and tags: " + sentTags.size()); return new WrappedMessage(msg, skm, sentTo, sentKey, tsh); } @@ -103,8 +103,8 @@ class MessageWrapper { void acked() { if (this.tsh != null) { this.skm.tagsAcked(this.sentTo, this.sessionKey, this.tsh); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Tags acked for key: " + this.sessionKey); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Tags acked for key: " + this.sessionKey); } } @@ -112,8 +112,8 @@ class MessageWrapper { void fail() { if (this.tsh != null) { this.skm.failTags(this.sentTo, this.sessionKey, this.tsh); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Tags NOT acked for key: " + this.sessionKey); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Tags NOT acked for key: " + this.sessionKey); } } } diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPAddress.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPAddress.java index acced89f43..a51233ad63 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPAddress.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPAddress.java @@ -11,6 +11,7 @@ package net.i2p.router.transport.ntcp; import java.net.InetAddress; import java.util.Properties; +import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.data.RouterAddress; import net.i2p.router.transport.TransportImpl; @@ -20,7 +21,6 @@ import net.i2p.util.Log; * Wrap up an address */ public class NTCPAddress { - private final static Log _log = new Log(NTCPAddress.class); private int _port; private String _host; //private InetAddress _addr; @@ -68,7 +68,8 @@ public class NTCPAddress { try { _port = Integer.parseInt(port.trim()); } catch (NumberFormatException nfe) { - _log.error("Invalid port [" + port + "]", nfe); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(NTCPAddress.class); + log.error("Invalid port [" + port + "]", nfe); _port = -1; } } else { @@ -119,8 +120,8 @@ public class NTCPAddress { //} return TransportImpl.isPubliclyRoutable(quad); } catch (Throwable t) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Error checking routability", t); + //if (_log.shouldLog(Log.WARN)) + // _log.warn("Error checking routability", t); return false; } } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java index c45a29bdb1..eb4c3e23c5 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -18,7 +18,6 @@ import net.i2p.util.Log; */ class UDPPacket { private I2PAppContext _context; - private static Log _log; private final DatagramPacket _packet; private volatile short _priority; private volatile long _initializeTime; @@ -48,7 +47,6 @@ class UDPPacket { _packetCache = new LinkedBlockingQueue(CACHE_SIZE); else _packetCache = null; - _log = I2PAppContext.getGlobalContext().logManager().getLog(UDPPacket.class); } /** @@ -214,8 +212,8 @@ class UDPPacket { eq = DataHelper.eq(hmac.getData(), 0, _data, _packet.getOffset(), MAC_SIZE); */ } else { - if (_log.shouldLog(Log.WARN)) - _log.warn("Payload length is " + payloadLength); + //if (_log.shouldLog(Log.WARN)) + // _log.warn("Payload length is " + payloadLength); } _afterValidate = _context.clock().now(); @@ -321,9 +319,10 @@ class UDPPacket { private void verifyNotReleased() { if (CACHE) return; if (_released) { - _log.log(Log.CRIT, "Already released. current stack trace is:", new Exception()); - _log.log(Log.CRIT, "Released by: ", _releasedBy); - _log.log(Log.CRIT, "Acquired by: ", _acquiredBy); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(UDPPacket.class); + log.log(Log.CRIT, "Already released. current stack trace is:", new Exception()); + log.log(Log.CRIT, "Released by: ", _releasedBy); + log.log(Log.CRIT, "Acquired by: ", _acquiredBy); } } } From 2bc70b53c1d02a38781073a8943f6e219fbd2337 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 29 Feb 2012 13:45:02 +0000 Subject: [PATCH 25/44] debug log --- .../src/net/i2p/router/networkdb/reseed/ReseedChecker.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java b/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java index 6bb816985d..ea3e0408d3 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java @@ -32,14 +32,16 @@ public class ReseedChecker { File noReseedFileAlt1 = new File(new File(System.getProperty("user.home")), "noreseed.i2p"); File noReseedFileAlt2 = new File(context.getConfigDir(), ".i2pnoreseed"); File noReseedFileAlt3 = new File(context.getConfigDir(), "noreseed.i2p"); + Log _log = context.logManager().getLog(ReseedChecker.class); if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) { - Log _log = context.logManager().getLog(ReseedChecker.class); if (count <= 1) _log.logAlways(Log.INFO, "Downloading peer router information for a new I2P installation"); else _log.logAlways(Log.WARN, "Very few known peers remaining - reseeding now"); Reseeder reseeder = new Reseeder(context); reseeder.requestReseed(); + } else { + _log.logAlways(Log.WARN, "Only " + count + " peers remaining but reseed disabled by config file"); } } } From 48551f06177feb95fe689e6a4da2c073947adfd6 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 29 Feb 2012 17:50:54 +0000 Subject: [PATCH 26/44] NetDB: Reenable RI store verifies. Was disabled in 0.7.9; checkin comments claim it was reenabled in 0.7.10 but it didn't actually happen, probably due to bad merge. --- .../net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java index edc760c3d8..581566287d 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillStoreJob.java @@ -68,10 +68,7 @@ class FloodfillStoreJob extends StoreJob { DatabaseEntry data = _state.getData(); boolean isRouterInfo = data.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO; long published = data.getDate(); - if (isRouterInfo) { - // Temporarily disable - return; - } + // we should always have exactly one successful entry Hash sentTo = null; try { From f61183d2d85bb76cdf2b4db972951ffa34987b82 Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 29 Feb 2012 18:09:16 +0000 Subject: [PATCH 27/44] * DataStructures: - Remove static logs - Sort addresses in RouterInfo at initialization only; change from Set to List to save space - Remove unused counters in Lease to save space - Increase max leases to 16 --- core/java/src/net/i2p/data/DataHelper.java | 12 +++- core/java/src/net/i2p/data/LeaseSet.java | 42 ++++++++++---- core/java/src/net/i2p/data/RouterInfo.java | 55 +++++++++++-------- router/java/src/net/i2p/router/Blocklist.java | 8 +-- .../kademlia/FloodfillVerifyStoreJob.java | 2 +- ...andleFloodfillDatabaseStoreMessageJob.java | 9 +-- .../router/peermanager/ProfileOrganizer.java | 3 +- 7 files changed, 83 insertions(+), 48 deletions(-) diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index d809926098..ad6ac6ea9d 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -1299,10 +1299,20 @@ public class DataHelper { // rv.add(struct); //} ArrayList rv = new ArrayList(dataStructures); - Collections.sort(rv, new DataStructureComparator()); + sortStructureList(rv); return rv; } + /** + * See above. + * DEPRECATED - Only used by RouterInfo. + * + * @since 0.9 + */ + static void sortStructureList(List dataStructures) { + Collections.sort(dataStructures, new DataStructureComparator()); + } + /** * See sortStructures() comments. * @since 0.8.3 diff --git a/core/java/src/net/i2p/data/LeaseSet.java b/core/java/src/net/i2p/data/LeaseSet.java index e372f401cd..9fe9ebb304 100644 --- a/core/java/src/net/i2p/data/LeaseSet.java +++ b/core/java/src/net/i2p/data/LeaseSet.java @@ -56,7 +56,6 @@ import net.i2p.util.RandomSource; * @author jrandom */ public class LeaseSet extends DatabaseEntry { - private final static Log _log = new Log(LeaseSet.class); private Destination _destination; private PublicKey _encryptionKey; private SigningPublicKey _signingKey; @@ -71,11 +70,26 @@ public class LeaseSet extends DatabaseEntry { private boolean _decrypted; private boolean _checked; - /** This seems like plenty */ - public final static int MAX_LEASES = 6; + /** + * Unlimited before 0.6.3; + * 6 as of 0.6.3; + * Increased in version 0.9. + * + * Leasesets larger than 6 should be used with caution, + * as each lease adds 44 bytes, and routers older than version 0.9 + * will not be able to connect as they will throw an exception in + * readBytes(). Also, the churn will be quite rapid, leading to + * frequent netdb stores and transmission on existing connections. + * + * However we increase it now in case some hugely popular eepsite arrives. + * Strategies elsewhere in the router to efficiently handle + * large leasesets are TBD. + */ + public static final int MAX_LEASES = 16; + private static final int OLD_MAX_LEASES = 6; public LeaseSet() { - _leases = new ArrayList(MAX_LEASES); + _leases = new ArrayList(OLD_MAX_LEASES); _firstExpiration = Long.MAX_VALUE; } @@ -354,14 +368,16 @@ public class LeaseSet extends DatabaseEntry { * Must be called after all the leases are in place, but before sign(). */ public void encrypt(SessionKey key) { - if (_log.shouldLog(Log.WARN)) - _log.warn("encrypting lease: " + _destination.calculateHash()); + //if (_log.shouldLog(Log.WARN)) + // _log.warn("encrypting lease: " + _destination.calculateHash()); try { encryp(key); } catch (DataFormatException dfe) { - _log.error("Error encrypting lease: " + _destination.calculateHash()); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class); + log.error("Error encrypting lease: " + _destination.calculateHash()); } catch (IOException ioe) { - _log.error("Error encrypting lease: " + _destination.calculateHash()); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class); + log.error("Error encrypting lease: " + _destination.calculateHash()); } } @@ -420,8 +436,8 @@ public class LeaseSet extends DatabaseEntry { * encrypted leaseset can be sent on to others (via writeBytes()) */ private void decrypt(SessionKey key) throws DataFormatException, IOException { - if (_log.shouldLog(Log.WARN)) - _log.warn("decrypting lease: " + _destination.calculateHash()); + //if (_log.shouldLog(Log.WARN)) + // _log.warn("decrypting lease: " + _destination.calculateHash()); int size = _leases.size(); if (size < 2) throw new DataFormatException("Bad number of leases for decryption"); @@ -468,9 +484,11 @@ public class LeaseSet extends DatabaseEntry { decrypt(key); _decrypted = true; } catch (DataFormatException dfe) { - _log.error("Error decrypting lease: " + _destination.calculateHash() + dfe); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class); + log.error("Error decrypting lease: " + _destination.calculateHash() + dfe); } catch (IOException ioe) { - _log.error("Error decrypting lease: " + _destination.calculateHash() + ioe); + Log log = I2PAppContext.getGlobalContext().logManager().getLog(LeaseSet.class); + log.error("Error decrypting lease: " + _destination.calculateHash() + ioe); } } _checked = true; diff --git a/core/java/src/net/i2p/data/RouterInfo.java b/core/java/src/net/i2p/data/RouterInfo.java index 6c34ad2023..398b61e0c8 100644 --- a/core/java/src/net/i2p/data/RouterInfo.java +++ b/core/java/src/net/i2p/data/RouterInfo.java @@ -13,6 +13,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -24,6 +25,7 @@ import java.util.Properties; import java.util.Set; import java.util.Vector; +import net.i2p.I2PAppContext; import net.i2p.crypto.SHA256Generator; import net.i2p.util.Clock; import net.i2p.util.Log; @@ -43,10 +45,14 @@ import net.i2p.util.OrderedProperties; * @author jrandom */ public class RouterInfo extends DatabaseEntry { - private final static Log _log = new Log(RouterInfo.class); private RouterIdentity _identity; private volatile long _published; - private final Set _addresses; + /** + * Addresses must be sorted by SHA256. + * When an RI is created, they are sorted in setAddresses(). + * Save addresses in the order received so we need not resort. + */ + private final List _addresses; /** may be null to save memory, no longer final */ private Set _peers; private final Properties _options; @@ -71,7 +77,7 @@ public class RouterInfo extends DatabaseEntry { public static final String BW_CAPABILITY_CHARS = "KLMNO"; public RouterInfo() { - _addresses = new HashSet(2); + _addresses = new ArrayList(2); _options = new OrderedProperties(); } @@ -156,21 +162,33 @@ public class RouterInfo extends DatabaseEntry { * * @return unmodifiable view, non-null */ - public Set getAddresses() { - return Collections.unmodifiableSet(_addresses); + public Collection getAddresses() { + return Collections.unmodifiableCollection(_addresses); } /** * Specify a set of RouterAddress structures at which this router * can be contacted. * - * @throws IllegalStateException if RouterInfo is already signed + * Warning - Sorts the addresses here. Do not modify any address + * after calling this, as the sort order is based on the + * hash of the entire address structure. + * + * @param addresses may be null + * @throws IllegalStateException if RouterInfo is already signed or addresses previously set */ - public void setAddresses(Set addresses) { - if (_signature != null) + public void setAddresses(Collection addresses) { + if (_signature != null || !_addresses.isEmpty()) throw new IllegalStateException(); - _addresses.clear(); - if (addresses != null) _addresses.addAll(addresses); + if (addresses != null) { + _addresses.addAll(addresses); + if (_addresses.size() > 1) { + // WARNING this sort algorithm cannot be changed, as it must be consistent + // network-wide. The signature is not checked at readin time, but only + // later, and the addresses are stored in a Set, not a List. + DataHelper.sortStructureList(_addresses); + } + } } /** @@ -270,14 +288,7 @@ public class RouterInfo extends DatabaseEntry { DataHelper.writeLong(out, 1, 0); } else { DataHelper.writeLong(out, 1, sz); - Collection addresses = _addresses; - if (sz > 1) { - // WARNING this sort algorithm cannot be changed, as it must be consistent - // network-wide. The signature is not checked at readin time, but only - // later, and the addresses are stored in a Set, not a List. - addresses = (Collection) DataHelper.sortStructures(addresses); - } - for (RouterAddress addr : addresses) { + for (RouterAddress addr : _addresses) { addr.writeBytes(out); } } @@ -458,16 +469,16 @@ public class RouterInfo extends DatabaseEntry { _validated = true; if (!_isValid) { + Log log = I2PAppContext.getGlobalContext().logManager().getLog(RouterInfo.class); byte data[] = null; try { data = getBytes(); } catch (DataFormatException dfe) { - _log.error("Error validating", dfe); + log.error("Error validating", dfe); return; } - if (_log.shouldLog(Log.ERROR)) - _log.error("Invalid [" + SHA256Generator.getInstance().calculateHash(data).toBase64() - + (_log.shouldLog(Log.WARN) ? ("]\n" + toString()) : ""), + log.error("Invalid [" + SHA256Generator.getInstance().calculateHash(data).toBase64() + + (log.shouldLog(Log.WARN) ? ("]\n" + toString()) : ""), new Exception("Signature failed")); } } diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index 153b14e7c9..48ff328a2c 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -479,15 +479,9 @@ public class Blocklist { List rv = new ArrayList(1); RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer); if (pinfo == null) return rv; - Set paddr = pinfo.getAddresses(); - if (paddr == null || paddr.isEmpty()) - return rv; String oldphost = null; - List pladdr = new ArrayList(paddr); // for each peer address - for (int j = 0; j < paddr.size(); j++) { - RouterAddress pa = (RouterAddress) pladdr.get(j); - if (pa == null) continue; + for (RouterAddress pa : pinfo.getAddresses()) { String phost = pa.getOption("host"); if (phost == null) continue; if (oldphost != null && oldphost.equals(phost)) continue; diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java index 9fe6e25221..7b567d6126 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillVerifyStoreJob.java @@ -216,7 +216,7 @@ public class FloodfillVerifyStoreJob extends JobImpl { if (_log.shouldLog(Log.WARN)) _log.warn("Verify failed (older) for " + _key); if (_log.shouldLog(Log.INFO)) - _log.info("Rcvd older lease: " + dsm.getEntry()); + _log.info("Rcvd older data: " + dsm.getEntry()); } else if (_message instanceof DatabaseSearchReplyMessage) { // assume 0 old, all new, 0 invalid, 0 dup getContext().profileManager().dbLookupReply(_target, 0, diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java index 9774f65bd8..21c6a5ccd5 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/HandleFloodfillDatabaseStoreMessageJob.java @@ -8,12 +8,13 @@ package net.i2p.router.networkdb.kademlia; * */ +import java.util.Collection; import java.util.Date; -import java.util.Set; import net.i2p.data.DatabaseEntry; import net.i2p.data.Hash; import net.i2p.data.LeaseSet; +import net.i2p.data.RouterAddress; import net.i2p.data.RouterIdentity; import net.i2p.data.RouterInfo; import net.i2p.data.i2np.DatabaseStoreMessage; @@ -145,9 +146,9 @@ public class HandleFloodfillDatabaseStoreMessageJob extends JobImpl { _log.shouldLog(Log.WARN)) _log.warn("Blocklisting new peer " + key + ' ' + ri); } else { - Set oldAddr = prevNetDb.getAddresses(); - Set newAddr = ri.getAddresses(); - if (newAddr != null && (!newAddr.equals(oldAddr)) && + Collection oldAddr = prevNetDb.getAddresses(); + Collection newAddr = ri.getAddresses(); + if ((!newAddr.equals(oldAddr)) && (!getContext().shitlist().isShitlistedForever(key)) && getContext().blocklist().isBlocklisted(key) && _log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index 8b14d22a0f..d8459166a5 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -7,6 +7,7 @@ import java.net.UnknownHostException; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -1258,7 +1259,7 @@ public class ProfileOrganizer { RouterInfo pinfo = _context.netDb().lookupRouterInfoLocally(peer); if (pinfo == null) return rv; - Set paddr = pinfo.getAddresses(); + Collection paddr = pinfo.getAddresses(); if (paddr == null) return rv; for (RouterAddress pa : paddr) { From 538427c2696df77f7bb6cce5a17732cfcde36c4f Mon Sep 17 00:00:00 2001 From: zzz Date: Wed, 29 Feb 2012 18:49:49 +0000 Subject: [PATCH 28/44] - Synchronize StoreJob.sendNext() to avoid dups - StoreState finals --- .../net/i2p/router/networkdb/kademlia/StoreJob.java | 5 ++++- .../i2p/router/networkdb/kademlia/StoreState.java | 12 ++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java index 4620e3cffa..e86b9b6807 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreJob.java @@ -98,6 +98,8 @@ class StoreJob extends JobImpl { /** * send the key to the next batch of peers + * + * Synchronized to enforce parallelization limits and prevent dups */ private void sendNext() { if (_state.completed()) { @@ -130,8 +132,9 @@ class StoreJob extends JobImpl { * the routing table, but making sure no more than PARALLELIZATION are outstanding * at any time * + * Caller should synchronize to enforce parallelization limits and prevent dups */ - private void continueSending() { + private synchronized void continueSending() { if (_state.completed()) return; int toCheck = getParallelization() - _state.getPending().size(); if (toCheck <= 0) { diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java b/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java index 9666c09be5..876e2f4af8 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/StoreState.java @@ -14,15 +14,15 @@ import net.i2p.data.Hash; import net.i2p.router.RouterContext; /** - * + * Tracks the state of a StoreJob */ class StoreState { - private RouterContext _context; - private Hash _key; - private DatabaseEntry _data; + private final RouterContext _context; + private final Hash _key; + private final DatabaseEntry _data; private final HashSet _pendingPeers; - private Map _pendingPeerTimes; - private Map _pendingMessages; + private final Map _pendingPeerTimes; + private final Map _pendingMessages; private final HashSet _successfulPeers; //private final HashSet _successfulExploratoryPeers; private final HashSet _failedPeers; From b6f7321497bd599f4b9defd3673abb46ed5102e3 Mon Sep 17 00:00:00 2001 From: str4d Date: Thu, 1 Mar 2012 05:03:29 +0000 Subject: [PATCH 29/44] Fix the UTF8 POSTing issue --- apps/i2ptunnel/jsp/wizard.jsp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/i2ptunnel/jsp/wizard.jsp b/apps/i2ptunnel/jsp/wizard.jsp index ddb6556991..74afb65a28 100644 --- a/apps/i2ptunnel/jsp/wizard.jsp +++ b/apps/i2ptunnel/jsp/wizard.jsp @@ -1,6 +1,10 @@ <% // NOTE: Do the header carefully so there is no whitespace before the <%@page pageEncoding="UTF-8" %><%@page contentType="text/html" import="net.i2p.i2ptunnel.web.EditBean" %> From cf41068fefe40a896525e83fdbbaca7b61f89612 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 1 Mar 2012 13:41:24 +0000 Subject: [PATCH 30/44] SDK message --- build.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/build.xml b/build.xml index fa9746e537..9c9105e748 100644 --- a/build.xml +++ b/build.xml @@ -546,6 +546,7 @@ + From 5af6c97bee294019df2ca9e86a0b67459d116154 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 1 Mar 2012 14:21:54 +0000 Subject: [PATCH 31/44] log tweaks, final --- .../router/client/ClientConnectionRunner.java | 11 +++++----- .../i2p/router/client/RequestLeaseSetJob.java | 22 +++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java index a7a136d1dd..8597c52b2b 100644 --- a/router/java/src/net/i2p/router/client/ClientConnectionRunner.java +++ b/router/java/src/net/i2p/router/client/ClientConnectionRunner.java @@ -239,13 +239,13 @@ class ClientConnectionRunner { } /** - * Send a DisconnectMessage and log with level Log.CRIT. + * Send a DisconnectMessage and log with level Log.ERROR. * This is always bad. * See ClientMessageEventListener.handleCreateSession() * for why we don't send a SessionStatusMessage when we do this. */ void disconnectClient(String reason) { - disconnectClient(reason, Log.CRIT); + disconnectClient(reason, Log.ERROR); } /** @@ -254,9 +254,10 @@ class ClientConnectionRunner { */ void disconnectClient(String reason, int logLevel) { if (_log.shouldLog(logLevel)) - _log.log(logLevel, "Disconnecting the client (" - + _config - + ") : " + reason); + _log.log(logLevel, "Disconnecting the client - " + + reason + + " config: " + + _config); DisconnectMessage msg = new DisconnectMessage(); msg.setReason(reason); try { diff --git a/router/java/src/net/i2p/router/client/RequestLeaseSetJob.java b/router/java/src/net/i2p/router/client/RequestLeaseSetJob.java index 516a652d22..1ac0b93d04 100644 --- a/router/java/src/net/i2p/router/client/RequestLeaseSetJob.java +++ b/router/java/src/net/i2p/router/client/RequestLeaseSetJob.java @@ -27,13 +27,13 @@ import net.i2p.util.Log; * */ class RequestLeaseSetJob extends JobImpl { - private Log _log; - private ClientConnectionRunner _runner; - private LeaseSet _ls; - private long _expiration; - private Job _onCreate; - private Job _onFail; - private LeaseRequestState _requestState; + private final Log _log; + private final ClientConnectionRunner _runner; + private final LeaseSet _ls; + private final long _expiration; + private final Job _onCreate; + private final Job _onFail; + private final LeaseRequestState _requestState; public RequestLeaseSetJob(RouterContext ctx, ClientConnectionRunner runner, LeaseSet set, long expiration, Job onCreate, Job onFail, LeaseRequestState state) { super(ctx); @@ -92,8 +92,8 @@ class RequestLeaseSetJob extends JobImpl { * */ private class CheckLeaseRequestStatus extends JobImpl { - private LeaseRequestState _req; - private long _start; + private final LeaseRequestState _req; + private final long _start; public CheckLeaseRequestStatus(RouterContext enclosingContext, LeaseRequestState state) { super(enclosingContext); @@ -114,9 +114,9 @@ class RequestLeaseSetJob extends JobImpl { return; } else { RequestLeaseSetJob.CheckLeaseRequestStatus.this.getContext().statManager().addRateData("client.requestLeaseSetTimeout", 1, 0); - if (_log.shouldLog(Log.CRIT)) { + if (_log.shouldLog(Log.ERROR)) { long waited = System.currentTimeMillis() - _start; - _log.log(Log.CRIT, "Failed to receive a leaseSet in the time allotted (" + waited + "): " + _req + " for " + _log.error("Failed to receive a leaseSet in the time allotted (" + waited + "): " + _req + " for " + _runner.getConfig().getDestination().calculateHash().toBase64()); } _runner.disconnectClient("Took too long to request leaseSet"); From cadedeb06cdbacf36d38ec96e70ca44d5abaa0f1 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 1 Mar 2012 16:04:17 +0000 Subject: [PATCH 32/44] * Build: Add built-by to jars; check for corrupt jars on debug page --- apps/addressbook/build.xml | 2 ++ apps/i2psnark/java/build.xml | 2 ++ apps/i2ptunnel/java/build.xml | 2 ++ apps/jetty/build.xml | 1 + apps/ministreaming/java/build.xml | 1 + apps/routerconsole/java/build.xml | 2 ++ .../src/net/i2p/router/web/FileDumpHelper.java | 11 +++++++++-- apps/sam/java/build.xml | 2 ++ apps/streaming/java/build.xml | 1 + apps/susidns/src/build.xml | 1 + apps/susimail/build.xml | 1 + apps/systray/java/build.xml | 1 + build.properties | 2 ++ build.xml | 15 +++++++++++++++ core/java/build.xml | 1 + router/java/build.xml | 1 + 16 files changed, 44 insertions(+), 2 deletions(-) diff --git a/apps/addressbook/build.xml b/apps/addressbook/build.xml index ad27a00905..beff280f8c 100644 --- a/apps/addressbook/build.xml +++ b/apps/addressbook/build.xml @@ -56,6 +56,7 @@ + @@ -75,6 +76,7 @@ + diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index bded42a27f..3065ed9bc3 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -61,6 +61,7 @@ + @@ -108,6 +109,7 @@ + diff --git a/apps/i2ptunnel/java/build.xml b/apps/i2ptunnel/java/build.xml index 1b62279145..df8387b6d2 100644 --- a/apps/i2ptunnel/java/build.xml +++ b/apps/i2ptunnel/java/build.xml @@ -63,6 +63,7 @@ + @@ -136,6 +137,7 @@ basedir="../jsp/" excludes="web.xml, web-fragment.xml, web-out.xml, **/*.java, *.jsp"> + diff --git a/apps/jetty/build.xml b/apps/jetty/build.xml index e686e364a7..de9534274b 100644 --- a/apps/jetty/build.xml +++ b/apps/jetty/build.xml @@ -117,6 +117,7 @@ + diff --git a/apps/ministreaming/java/build.xml b/apps/ministreaming/java/build.xml index 235088fc31..451ecf0f4c 100644 --- a/apps/ministreaming/java/build.xml +++ b/apps/ministreaming/java/build.xml @@ -51,6 +51,7 @@ + diff --git a/apps/routerconsole/java/build.xml b/apps/routerconsole/java/build.xml index 3dba335781..714bd17db5 100644 --- a/apps/routerconsole/java/build.xml +++ b/apps/routerconsole/java/build.xml @@ -92,6 +92,7 @@ + @@ -172,6 +173,7 @@ basedir="../jsp/" excludes="web.xml, *.css, **/*.java, *.jsp, *.jsi, web-fragment.xml, web-out.xml"> + diff --git a/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java index eea306aa20..99026be16a 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java @@ -18,6 +18,7 @@ import java.util.jar.Manifest; import net.i2p.crypto.SHA256Generator; import net.i2p.data.DataHelper; +import net.i2p.util.FileUtil; /** * Dump info on jars and wars @@ -29,7 +30,7 @@ public class FileDumpHelper extends HelperBase { public String getFileSummary() { StringBuilder buf = new StringBuilder(16*1024); buf.append("
");
+        out.write("
"); + + writeMessages(out); + + if (isConfigure) { + // end of mainsection div + out.write("
\n"); + writeConfigForm(out, req); + writeTrackerForm(out, req); + } else { + writeTorrents(out, req); + // end of mainsection div + out.write("
\n"); + writeAddForm(out, req); + writeSeedForm(out, req); + writeConfigLink(out); + // end of lowersection div + out.write("
\n"); + } + out.write(FOOTER); + } + + private void writeMessages(PrintWriter out) throws IOException { + out.write("
");
         List msgs = _manager.getMessages();
         for (int i = msgs.size()-1; i >= 0; i--) {
             String msg = (String)msgs.get(i);
             out.write(msg + "\n");
         }
         out.write("
"); - - if (isConfigure) { - out.write("
\n"); - writeConfigForm(out, req); - writeTrackerForm(out, req); - } else { - writeTorrents(out, req); - out.write("\n"); - writeAddForm(out, req); - writeSeedForm(out, req); - writeConfigLink(out); - } - out.write(FOOTER); } private void writeTorrents(PrintWriter out, HttpServletRequest req) throws IOException { @@ -1356,7 +1383,7 @@ public class I2PSnarkServlet extends Default { ""); } - private static final int[] times = { 30, 60, 2*60, 5*60, 10*60, 30*60, -1 }; + private static final int[] times = { 5, 15, 30, 60, 2*60, 5*60, 10*60, 30*60, -1 }; private void writeConfigForm(PrintWriter out, HttpServletRequest req) throws IOException { String dataDir = _manager.getDataDir().getAbsolutePath(); diff --git a/apps/i2psnark/js/i2psnark.js b/apps/i2psnark/js/i2psnark.js new file mode 100644 index 0000000000..ba0e3f9115 --- /dev/null +++ b/apps/i2psnark/js/i2psnark.js @@ -0,0 +1,37 @@ +//var page = "home"; +function ajax(url,target) { + // native XMLHttpRequest object + if (window.XMLHttpRequest) { + req = new XMLHttpRequest(); + req.onreadystatechange = function() {ajaxDone(target);}; + req.open("GET", url, true); + req.send(null); + // IE/Windows ActiveX version + } else if (window.ActiveXObject) { + req = new ActiveXObject("Microsoft.XMLDOM"); + if (req) { + req.onreadystatechange = function() {ajaxDone(target);}; + req.open("GET", url, true); + req.send(null); + } + } + //setTimeout("ajax(page,'scriptoutput')", 5000); +} + +function ajaxDone(target) { + // only if req is "loaded" + if (req.readyState == 4) { + // only if "OK" + if (req.status == 200) { + results = req.responseText; + document.getElementById(target).innerHTML = results; + document.getElementById("lowersection").style.display="block"; + } else { + document.getElementById(target).innerHTML="Router is down"; + document.getElementById("lowersection").style.display="none"; + } + } +} + +function requestAjax1() { ajax("/i2psnark/.ajax/xhr1.html", "mainsection"); } +function initAjax(delayMs) { setInterval(requestAjax1, delayMs); } From 87da4b78ab08f3fb3eaeecf0a28c6a57a45acbab Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 23 Feb 2012 19:06:21 +0000 Subject: [PATCH 10/44] add negative cache to BFNS --- .../client/naming/BlockfileNamingService.java | 22 ++++++++++++++++++- .../i2p/client/naming/DummyNamingService.java | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/core/java/src/net/i2p/client/naming/BlockfileNamingService.java b/core/java/src/net/i2p/client/naming/BlockfileNamingService.java index 6d0e1bb6f3..8172ee7fd2 100644 --- a/core/java/src/net/i2p/client/naming/BlockfileNamingService.java +++ b/core/java/src/net/i2p/client/naming/BlockfileNamingService.java @@ -92,6 +92,7 @@ public class BlockfileNamingService extends DummyNamingService { private final RAIFile _raf; private final List _lists; private final List _invalid; + private final Map _negativeCache; private volatile boolean _isClosed; private final boolean _readOnly; private boolean _needsUpgrade; @@ -118,6 +119,9 @@ public class BlockfileNamingService extends DummyNamingService { private static final String PROP_ADDED = "a"; private static final String PROP_SOURCE = "s"; + private static final String DUMMY = ""; + private static final int NEGATIVE_CACHE_SIZE = 32; + /** * Opens the database at hostsdb.blockfile or creates a new * one and imports entries from hosts.txt, userhosts.txt, and privatehosts.txt. @@ -132,6 +136,7 @@ public class BlockfileNamingService extends DummyNamingService { super(context); _lists = new ArrayList(); _invalid = new ArrayList(); + _negativeCache = new LHM(NEGATIVE_CACHE_SIZE); BlockFile bf = null; RAIFile raf = null; boolean readOnly = false; @@ -628,6 +633,10 @@ public class BlockfileNamingService extends DummyNamingService { } String key = hostname.toLowerCase(Locale.US); + synchronized(_negativeCache) { + if (_negativeCache.get(key) != null) + return null; + } synchronized(_bf) { if (_isClosed) return null; @@ -650,8 +659,13 @@ public class BlockfileNamingService extends DummyNamingService { } deleteInvalid(); } - if (d != null) + if (d != null) { putCache(hostname, d); + } else { + synchronized(_negativeCache) { + _negativeCache.put(key, DUMMY); + } + } return d; } @@ -683,6 +697,9 @@ public class BlockfileNamingService extends DummyNamingService { return false; } String key = hostname.toLowerCase(Locale.US); + synchronized(_negativeCache) { + _negativeCache.remove(key); + } String listname = FALLBACK_LIST; Properties props = new Properties(); props.setProperty(PROP_ADDED, Long.toString(_context.clock().now())); @@ -1031,6 +1048,9 @@ public class BlockfileNamingService extends DummyNamingService { } _isClosed = true; } + synchronized(_negativeCache) { + _negativeCache.clear(); + } clearCache(); } diff --git a/core/java/src/net/i2p/client/naming/DummyNamingService.java b/core/java/src/net/i2p/client/naming/DummyNamingService.java index 21f8a7c7cc..63c6cf2648 100644 --- a/core/java/src/net/i2p/client/naming/DummyNamingService.java +++ b/core/java/src/net/i2p/client/naming/DummyNamingService.java @@ -116,7 +116,7 @@ class DummyNamingService extends NamingService { } } - private static class LHM extends LinkedHashMap { + protected static class LHM extends LinkedHashMap { private final int _max; public LHM(int max) { From eeb9ee0852b666dddd7be2fa2ac4065b1ab8a4e7 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 23 Feb 2012 19:31:25 +0000 Subject: [PATCH 11/44] snark conn limits --- apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index 254f74c44b..81c56a1947 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -219,6 +219,10 @@ public class I2PSnarkUtil { // opts.setProperty("i2p.streaming.writeTimeout", "90000"); //if (opts.getProperty("i2p.streaming.readTimeout") == null) // opts.setProperty("i2p.streaming.readTimeout", "120000"); + if (opts.getProperty("i2p.streaming.maxConnsPerMinute") == null) + opts.setProperty("i2p.streaming.maxConnsPerMinute", "2"); + if (opts.getProperty("i2p.streaming.maxTotalConnsPerMinute") == null) + opts.setProperty("i2p.streaming.maxTotalConnsPerMinute", "6"); _manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts); } // FIXME this only instantiates krpc once, left stuck with old manager From 54f0cae2ff3ba36b8c9a7eb1f6ec795948a52ba7 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 24 Feb 2012 17:58:54 +0000 Subject: [PATCH 12/44] refactor proxy.i2p server to its own class --- .../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 205 +-------------- .../localServer/LocalHTTPServer.java | 248 ++++++++++++++++++ 2 files changed, 255 insertions(+), 198 deletions(-) create mode 100644 apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index b3bce9cbcd..4980425c69 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -36,8 +36,8 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.data.Hash; +import net.i2p.i2ptunnel.localServer.LocalHTTPServer; import net.i2p.util.EventDispatcher; -import net.i2p.util.FileUtil; import net.i2p.util.Log; import net.i2p.util.PortMapper; import net.i2p.util.Translate; @@ -309,7 +309,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn return rv; } - private static final String LOCAL_SERVER = "proxy.i2p"; + public static final String LOCAL_SERVER = "proxy.i2p"; private static final boolean DEFAULT_GZIP = true; /** all default to false */ public static final String PROP_REFERER = "i2ptunnel.httpclient.sendReferer"; @@ -798,7 +798,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) { out.write(ERR_HELPER_DISABLED); } else { - serveLocalFile(out, method, targetRequest, _proxyNonce); + LocalHTTPServer.serveLocalFile(out, method, targetRequest, _proxyNonce); } s.close(); return; @@ -1046,7 +1046,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // we won't ever get here } - private static void writeFooter(OutputStream out) throws IOException { + /** + * Public only for LocalHTTPServer, not for general use + */ + public static void writeFooter(OutputStream out) throws IOException { // the css is hiding this div for now, but we'll keep it here anyway out.write("

I2P HTTP Proxy Server
Generated on: ".getBytes()); out.write(new Date().toString().getBytes()); @@ -1196,20 +1199,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn return protocol.toLowerCase(Locale.US).equals("http://"); } - private final static byte[] ERR_404 = - ("HTTP/1.1 404 Not Found\r\n"+ - "Content-Type: text/plain\r\n"+ - "\r\n"+ - "HTTP Proxy local file not found") - .getBytes(); - - private final static byte[] ERR_ADD = - ("HTTP/1.1 409 Bad\r\n"+ - "Content-Type: text/plain\r\n"+ - "\r\n"+ - "Add to addressbook failed - bad parameters") - .getBytes(); - private final static byte[] ERR_HELPER_DISABLED = ("HTTP/1.1 403 Disabled\r\n"+ "Content-Type: text/plain\r\n"+ @@ -1217,186 +1206,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn "Address helpers disabled") .getBytes(); - /** - * Very simple web server. - * - * Serve local files in the docs/ directory, for CSS and images in - * error pages, using the reserved address proxy.i2p - * (similar to p.p in privoxy). - * This solves the problems with including links to the router console, - * as assuming the router console is at 127.0.0.1 leads to broken - * links if it isn't. - * - * Ignore all request headers (If-Modified-Since, etc.) - * - * There is basic protection here - - * FileUtil.readFile() prevents traversal above the base directory - - * but inproxy/gateway ops would be wise to block proxy.i2p to prevent - * exposing the docs/ directory or perhaps other issues through - * uncaught vulnerabilities. - * Restrict to the /themes/ directory for now. - * - * @param targetRequest "proxy.i2p/themes/foo.png HTTP/1.1" - */ - private static void serveLocalFile(OutputStream out, String method, String targetRequest, String proxyNonce) { - //System.err.println("targetRequest: \"" + targetRequest + "\""); - // a home page message for the curious... - if (targetRequest.startsWith(LOCAL_SERVER + "/ ")) { - try { - out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes()); - out.flush(); - } catch (IOException ioe) {} - return; - } - if ((method.equals("GET") || method.equals("HEAD")) && - targetRequest.startsWith(LOCAL_SERVER + "/themes/") && - !targetRequest.contains("..")) { - int space = targetRequest.indexOf(' '); - String filename = null; - try { - filename = targetRequest.substring(LOCAL_SERVER.length() + 8, space); // "/themes/".length - } catch (IndexOutOfBoundsException ioobe) { - return; - } - // theme hack - if (filename.startsWith("console/default/")) - filename = filename.replaceFirst("default", I2PAppContext.getGlobalContext().getProperty("routerconsole.theme", "light")); - File themesDir = new File(_errorDir, "themes"); - File file = new File(themesDir, filename); - if (file.exists() && !file.isDirectory()) { - String type; - if (filename.endsWith(".css")) - type = "text/css"; - else if (filename.endsWith(".ico")) - type = "image/x-icon"; - else if (filename.endsWith(".png")) - type = "image/png"; - else if (filename.endsWith(".jpg")) - type = "image/jpeg"; - else type = "text/html"; - try { - out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes()); - out.write(type.getBytes()); - out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes()); - FileUtil.readFile(filename, themesDir.getAbsolutePath(), out); - } catch (IOException ioe) {} - return; - } - } - - // Add to addressbook (form submit) - // Parameters are url, host, dest, nonce, and master | router | private. - // Do the add and redirect. - if (targetRequest.startsWith(LOCAL_SERVER + "/add?")) { - int spc = targetRequest.indexOf(' '); - String query = targetRequest.substring(LOCAL_SERVER.length() + 5, spc); // "/add?".length() - Map opts = new HashMap(8); - StringTokenizer tok = new StringTokenizer(query, "=&;"); - while (tok.hasMoreTokens()) { - String k = tok.nextToken(); - if (!tok.hasMoreTokens()) - break; - String v = tok.nextToken(); - opts.put(decode(k), decode(v)); - } - - String url = opts.get("url"); - String host = opts.get("host"); - String b64Dest = opts.get("dest"); - String nonce = opts.get("nonce"); - String book = "privatehosts.txt"; - if (opts.get("master") != null) - book = "userhosts.txt"; - else if (opts.get("router") != null) - book = "hosts.txt"; - Destination dest = null; - if (b64Dest != null) { - try { - dest = new Destination(b64Dest); - } catch (DataFormatException dfe) { - System.err.println("Bad dest to save?" + b64Dest); - } - } - //System.err.println("url : \"" + url + "\""); - //System.err.println("host : \"" + host + "\""); - //System.err.println("b64dest : \"" + b64Dest + "\""); - //System.err.println("book : \"" + book + "\""); - //System.err.println("nonce : \"" + nonce + "\""); - if (proxyNonce.equals(nonce) && url != null && host != null && dest != null) { - try { - NamingService ns = I2PAppContext.getGlobalContext().namingService(); - Properties nsOptions = new Properties(); - nsOptions.setProperty("list", book); - nsOptions.setProperty("s", _("Added via address helper")); - boolean success = ns.put(host, dest, nsOptions); - writeRedirectPage(out, success, host, book, url); - return; - } catch (IOException ioe) {} - } - try { - out.write(ERR_ADD); - out.flush(); - } catch (IOException ioe) {} - return; - } - try { - out.write(ERR_404); - out.flush(); - } catch (IOException ioe) {} - } - - /** @since 0.8.7 */ - private static void writeRedirectPage(OutputStream out, boolean success, String host, String book, String url) throws IOException { - out.write(("HTTP/1.1 200 OK\r\n"+ - "Content-Type: text/html; charset=UTF-8\r\n"+ - "\r\n"+ - ""+ - "" + _("Redirecting to {0}", host) + "\n" + - "\n" + - "\n" + - "\n" + - "\n" + - "

" + - "
\n" + - "

" + - (success ? - _("Saved {0} to the {1} addressbook, redirecting now.", host, book) : - _("Failed to save {0} to the {1} addressbook, redirecting now.", host, book)) + - "

\n

" + - _("Click here if you are not redirected automatically.") + - "

").getBytes("UTF-8")); - writeFooter(out); - out.flush(); - } - - /** - * Decode %xx encoding - * @since 0.8.7 - */ - private static String decode(String s) { - if (!s.contains("%")) - return s; - StringBuilder buf = new StringBuilder(s.length()); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c != '%') { - buf.append(c); - } else { - try { - buf.append((char) Integer.parseInt(s.substring(++i, (++i) + 1), 16)); - } catch (IndexOutOfBoundsException ioobe) { - break; - } catch (NumberFormatException nfe) { - break; - } - } - } - return buf.toString(); - } - private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.web.messages"; /** lang in routerconsole.lang property, else current locale */ diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java new file mode 100644 index 0000000000..0140b609cd --- /dev/null +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java @@ -0,0 +1,248 @@ +/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java) + * (c) 2003 - 2004 mihi + */ +package net.i2p.i2ptunnel.localServer; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; + +import net.i2p.I2PAppContext; +import net.i2p.client.naming.NamingService; +import net.i2p.data.DataFormatException; +import net.i2p.data.Destination; +import net.i2p.i2ptunnel.I2PTunnelHTTPClient; +import net.i2p.util.FileUtil; +import net.i2p.util.Log; +import net.i2p.util.Translate; + +/** + * Very simple web server. + * + * Serve local files in the docs/ directory, for CSS and images in + * error pages, using the reserved address proxy.i2p + * (similar to p.p in privoxy). + * This solves the problems with including links to the router console, + * as assuming the router console is at 127.0.0.1 leads to broken + * links if it isn't. + * + * @since 0.7.6, moved from I2PTunnelHTTPClient in 0.9 + */ +public abstract class LocalHTTPServer { + + private final static byte[] ERR_404 = + ("HTTP/1.1 404 Not Found\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "HTTP Proxy local file not found") + .getBytes(); + + private final static byte[] ERR_ADD = + ("HTTP/1.1 409 Bad\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "Add to addressbook failed - bad parameters") + .getBytes(); + + /** + * Very simple web server. + * + * Serve local files in the docs/ directory, for CSS and images in + * error pages, using the reserved address proxy.i2p + * (similar to p.p in privoxy). + * This solves the problems with including links to the router console, + * as assuming the router console is at 127.0.0.1 leads to broken + * links if it isn't. + * + * Ignore all request headers (If-Modified-Since, etc.) + * + * There is basic protection here - + * FileUtil.readFile() prevents traversal above the base directory - + * but inproxy/gateway ops would be wise to block proxy.i2p to prevent + * exposing the docs/ directory or perhaps other issues through + * uncaught vulnerabilities. + * Restrict to the /themes/ directory for now. + * + * @param targetRequest "proxy.i2p/themes/foo.png HTTP/1.1" + */ + public static void serveLocalFile(OutputStream out, String method, String targetRequest, String proxyNonce) { + //System.err.println("targetRequest: \"" + targetRequest + "\""); + // a home page message for the curious... + if (targetRequest.startsWith(I2PTunnelHTTPClient.LOCAL_SERVER + "/ ")) { + try { + out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes()); + out.flush(); + } catch (IOException ioe) {} + return; + } + if ((method.equals("GET") || method.equals("HEAD")) && + targetRequest.startsWith(I2PTunnelHTTPClient.LOCAL_SERVER + "/themes/") && + !targetRequest.contains("..")) { + int space = targetRequest.indexOf(' '); + String filename = null; + try { + filename = targetRequest.substring(I2PTunnelHTTPClient.LOCAL_SERVER.length() + 8, space); // "/themes/".length + } catch (IndexOutOfBoundsException ioobe) { + return; + } + // theme hack + if (filename.startsWith("console/default/")) + filename = filename.replaceFirst("default", I2PAppContext.getGlobalContext().getProperty("routerconsole.theme", "light")); + File themesDir = new File(I2PAppContext.getGlobalContext().getBaseDir(), "docs/themes"); + File file = new File(themesDir, filename); + if (file.exists() && !file.isDirectory()) { + String type; + if (filename.endsWith(".css")) + type = "text/css"; + else if (filename.endsWith(".ico")) + type = "image/x-icon"; + else if (filename.endsWith(".png")) + type = "image/png"; + else if (filename.endsWith(".jpg")) + type = "image/jpeg"; + else type = "text/html"; + try { + out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes()); + out.write(type.getBytes()); + out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes()); + FileUtil.readFile(filename, themesDir.getAbsolutePath(), out); + } catch (IOException ioe) {} + return; + } + } + + // Add to addressbook (form submit) + // Parameters are url, host, dest, nonce, and master | router | private. + // Do the add and redirect. + if (targetRequest.startsWith(I2PTunnelHTTPClient.LOCAL_SERVER + "/add?")) { + int spc = targetRequest.indexOf(' '); + String query = targetRequest.substring(I2PTunnelHTTPClient.LOCAL_SERVER.length() + 5, spc); // "/add?".length() + Map opts = new HashMap(8); + StringTokenizer tok = new StringTokenizer(query, "=&;"); + while (tok.hasMoreTokens()) { + String k = tok.nextToken(); + if (!tok.hasMoreTokens()) + break; + String v = tok.nextToken(); + opts.put(decode(k), decode(v)); + } + + String url = opts.get("url"); + String host = opts.get("host"); + String b64Dest = opts.get("dest"); + String nonce = opts.get("nonce"); + String book = "privatehosts.txt"; + if (opts.get("master") != null) + book = "userhosts.txt"; + else if (opts.get("router") != null) + book = "hosts.txt"; + Destination dest = null; + if (b64Dest != null) { + try { + dest = new Destination(b64Dest); + } catch (DataFormatException dfe) { + System.err.println("Bad dest to save?" + b64Dest); + } + } + //System.err.println("url : \"" + url + "\""); + //System.err.println("host : \"" + host + "\""); + //System.err.println("b64dest : \"" + b64Dest + "\""); + //System.err.println("book : \"" + book + "\""); + //System.err.println("nonce : \"" + nonce + "\""); + if (proxyNonce.equals(nonce) && url != null && host != null && dest != null) { + try { + NamingService ns = I2PAppContext.getGlobalContext().namingService(); + Properties nsOptions = new Properties(); + nsOptions.setProperty("list", book); + nsOptions.setProperty("s", _("Added via address helper")); + boolean success = ns.put(host, dest, nsOptions); + writeRedirectPage(out, success, host, book, url); + return; + } catch (IOException ioe) {} + } + try { + out.write(ERR_ADD); + out.flush(); + } catch (IOException ioe) {} + return; + } + try { + out.write(ERR_404); + out.flush(); + } catch (IOException ioe) {} + } + + /** @since 0.8.7 */ + private static void writeRedirectPage(OutputStream out, boolean success, String host, String book, String url) throws IOException { + out.write(("HTTP/1.1 200 OK\r\n"+ + "Content-Type: text/html; charset=UTF-8\r\n"+ + "\r\n"+ + ""+ + "" + _("Redirecting to {0}", host) + "\n" + + "\n" + + "\n" + + "\n" + + "\n" + + "" + + "
\n" + + "

" + + (success ? + _("Saved {0} to the {1} addressbook, redirecting now.", host, book) : + _("Failed to save {0} to the {1} addressbook, redirecting now.", host, book)) + + "

\n

" + + _("Click here if you are not redirected automatically.") + + "

").getBytes("UTF-8")); + I2PTunnelHTTPClient.writeFooter(out); + out.flush(); + } + + /** + * Decode %xx encoding + * @since 0.8.7 + */ + private static String decode(String s) { + if (!s.contains("%")) + return s; + StringBuilder buf = new StringBuilder(s.length()); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c != '%') { + buf.append(c); + } else { + try { + buf.append((char) Integer.parseInt(s.substring(++i, (++i) + 1), 16)); + } catch (IndexOutOfBoundsException ioobe) { + break; + } catch (NumberFormatException nfe) { + break; + } + } + } + return buf.toString(); + } + + private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.web.messages"; + + /** lang in routerconsole.lang property, else current locale */ + protected static String _(String key) { + return Translate.getString(key, I2PAppContext.getGlobalContext(), BUNDLE_NAME); + } + + /** {0} */ + protected static String _(String key, Object o) { + return Translate.getString(key, o, I2PAppContext.getGlobalContext(), BUNDLE_NAME); + } + + /** {0} and {1} */ + protected static String _(String key, Object o, Object o2) { + return Translate.getString(key, o, o2, I2PAppContext.getGlobalContext(), BUNDLE_NAME); + } + +} From fc3343270a27be4c53c8c4e5793beeebb2f5ba8c Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 25 Feb 2012 18:40:27 +0000 Subject: [PATCH 13/44] fix LS count --- .../src/net/i2p/router/web/NetDbRenderer.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) 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 085ac31721..6b54c2988e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -33,6 +33,7 @@ import net.i2p.data.RouterInfo; import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.networkdb.kademlia.HashDistance; // debug +import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; import net.i2p.util.HexDump; // debug import net.i2p.util.ObjectCounter; import net.i2p.util.OrderedProperties; @@ -120,15 +121,16 @@ public class NetDbRenderer { } leases.addAll(_context.netDb().getLeases()); int medianCount = 0; + int rapCount = 0; BigInteger median = null; int c = 0; if (debug) { // Find the center of the RAP leasesets for (LeaseSet ls : leases) { if (ls.getReceivedAsPublished()) - medianCount++; + rapCount++; } - medianCount /= 2; + medianCount = rapCount / 2; } long now = _context.clock().now(); for (LeaseSet ls : leases) { @@ -181,18 +183,23 @@ public class NetDbRenderer { buf.setLength(0); } if (debug) { - buf.append("

Total Leasesets: " + leases.size()); - buf.append("

Published (RAP) Leasesets: " + _context.netDb().getKnownLeaseSets()); + FloodfillNetworkDatabaseFacade netdb = (FloodfillNetworkDatabaseFacade)_context.netDb(); + buf.append("

Total Leasesets: ").append(leases.size()); + buf.append("

Published (RAP) Leasesets: ").append(netdb.getKnownLeaseSets()); //buf.append("

Mod Data: " + HexDump.dump(_context.routingKeyGenerator().getModData())); + int ff = _context.peerManager().getPeersByCapability(FloodfillNetworkDatabaseFacade.CAPABILITY_FLOODFILL).size(); + buf.append("

Known Floodfills: ").append(ff); + buf.append("

Currently Floodfill? "); + buf.append(netdb.floodfillEnabled() ? "yes" : "no"); buf.append("

Network data (only valid if floodfill):"); //buf.append("

Center of Key Space (router hash): " + ourRKey.toBase64()); if (median != null) { double log2 = biLog2(median); - buf.append("

Median distance (bits): " + fmt.format(log2)); + buf.append("

Median distance (bits): ").append(fmt.format(log2)); // 3 for 8 floodfills... -1 for median int total = (int) Math.round(Math.pow(2, 3 + 256 - 1 - log2)); - buf.append("

Estimated total floodfills: " + total); - buf.append("

Estimated network total leasesets: " + (total * leases.size() / 8)); + buf.append("

Estimated total floodfills: ").append(total); + buf.append("

Estimated total leasesets: ").append(total * rapCount / 8); } buf.append("

"); } From da482c373e7db3766176250653647f4d2751c739 Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 26 Feb 2012 17:34:22 +0000 Subject: [PATCH 14/44] new single graph page --- .../src/net/i2p/router/web/GraphHelper.java | 196 ++++++++++++++++-- .../net/i2p/router/web/StatSummarizer.java | 19 +- .../net/i2p/router/web/SummaryListener.java | 11 +- .../net/i2p/router/web/SummaryRenderer.java | 18 +- apps/routerconsole/jsp/graph.jsp | 22 ++ apps/routerconsole/jsp/graphs.jsp | 1 - apps/routerconsole/jsp/viewstat.jsp | 5 +- 7 files changed, 243 insertions(+), 29 deletions(-) create mode 100644 apps/routerconsole/jsp/graph.jsp 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 b6a4ad2837..f31c7def56 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -20,6 +20,8 @@ public class GraphHelper extends FormHandler { private int _height; private int _refreshDelaySeconds; private boolean _persistent; + private String _stat; + private int _end; private static final String PROP_X = "routerconsole.graphX"; private static final String PROP_Y = "routerconsole.graphY"; @@ -32,6 +34,10 @@ public class GraphHelper extends FormHandler { private static final int DEFAULT_PERIODS = 60; static final int MAX_X = 2048; static final int MAX_Y = 1024; + private static final int MIN_X = 200; + private static final int MIN_Y = 60; + private static final int MIN_C = 20; + private static final int MAX_C = SummaryListener.MAX_ROWS; private static final int MIN_REFRESH = 15; /** set the defaults after we have a context */ @@ -64,17 +70,45 @@ public class GraphHelper extends FormHandler { public void storeWriter(Writer out) { _out = out; } public void setPeriodCount(String str) { - try { _periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {} + setC(str); } - public void setShowEvents(boolean b) { _showEvents = b; } + /** @since 0.9 */ + public void setE(String str) { + try { + _end = Math.max(0, Integer.parseInt(str)); + } catch (NumberFormatException nfe) {} + } + + /** @since 0.9 shorter parameter */ + public void setC(String str) { + try { + _periodCount = Math.max(MIN_C, Math.min(Integer.parseInt(str), MAX_C)); + } catch (NumberFormatException nfe) {} + } + + public void setShowEvents(String b) { _showEvents = !"false".equals(b); } public void setHeight(String str) { - try { _height = Math.min(Integer.parseInt(str), MAX_Y); } catch (NumberFormatException nfe) {} + setH(str); + } + + /** @since 0.9 shorter parameter */ + public void setH(String str) { + try { + _height = Math.max(MIN_Y, Math.min(Integer.parseInt(str), MAX_Y)); + } catch (NumberFormatException nfe) {} } public void setWidth(String str) { - try { _width = Math.min(Integer.parseInt(str), MAX_X); } catch (NumberFormatException nfe) {} + setW(str); + } + + /** @since 0.9 shorter parameter */ + public void setW(String str) { + try { + _width = Math.max(MIN_X, Math.min(Integer.parseInt(str), MAX_X)); + } catch (NumberFormatException nfe) {} } public void setRefreshDelay(String str) { @@ -89,6 +123,14 @@ public class GraphHelper extends FormHandler { /** @since 0.8.7 */ public void setPersistent(String foo) { _persistent = true; } + + /** + * For single stat page + * @since 0.9 + */ + public void setStat(String stat) { + _stat = stat; + } public String getImages() { if (StatSummarizer.isDisabled()) @@ -109,11 +151,11 @@ public class GraphHelper extends FormHandler { } if (hasTx && hasRx && !_showEvents) { - _out.write(""); + + "\">"); String title = _("Combined bandwidth graph"); _out.write(""); + + '.' + r.getPeriod() + + "&c=" + (3 * _periodCount) + + "&w=" + (3 * _width) + + "&h=" + (3 * _height) + + (_showEvents ? "&showEvents=1" : "") + + "\">"); _out.write(" rates = StatSummarizer.instance().parseSpecs(_stat); + if (rates.size() != 1) { + _out.write("Graphs not enabled for " + _stat); + return ""; + } + Rate r = rates.get(0); + _out.write("

"); + _out.write(_("{0} for {1}", r.getRateStat().getName(), DataHelper.formatDuration2(_periodCount * r.getPeriod()))); + if (_end > 0) + _out.write(' ' + _("ending {0} ago", DataHelper.formatDuration2(_end * r.getPeriod()))); + + _out.write("

\n"); + + if (_width < MAX_X && _height < MAX_Y) { + _out.write(link(_stat, _showEvents, _periodCount, _end, _width * 3 / 2, _height * 3 / 2)); + _out.write(_("Larger")); + _out.write(" - "); + } + + if (_width > MIN_X && _height > MIN_Y) { + _out.write(link(_stat, _showEvents, _periodCount, _end, _width * 2 / 3, _height * 2 / 3)); + _out.write(_("Smaller")); + _out.write(" - "); + } + + if (_height < MAX_Y) { + _out.write(link(_stat, _showEvents, _periodCount, _end, _width, _height * 3 / 2)); + _out.write(_("Taller")); + _out.write(" - "); + } + + if (_height > MIN_Y) { + _out.write(link(_stat, _showEvents, _periodCount, _end, _width, _height * 2 / 3)); + _out.write(_("Shorter")); + _out.write(" - "); + } + + if (_width < MAX_X) { + _out.write(link(_stat, _showEvents, _periodCount, _end, _width * 3 / 2, _height)); + _out.write(_("Wider")); + _out.write(" - "); + } + + if (_width > MIN_X) { + _out.write(link(_stat, _showEvents, _periodCount, _end, _width * 2 / 3, _height)); + _out.write(_("Narrower")); + _out.write(""); + } + + _out.write("
"); + if (_periodCount < MAX_C) { + _out.write(link(_stat, _showEvents, _periodCount * 2, _end, _width, _height)); + _out.write(_("Larger interval")); + _out.write(" - "); + } + + if (_periodCount > MIN_C) { + _out.write(link(_stat, _showEvents, _periodCount / 2, _end, _width, _height)); + _out.write(_("Smaller interval")); + _out.write(""); + } + + _out.write("
"); + if (_periodCount < MAX_C) { + _out.write(link(_stat, _showEvents, _periodCount, _end + _periodCount, _width, _height)); + _out.write(_("Previous interval")); + _out.write(""); + } + + if (_end > 0) { + int end = _end - _periodCount; + if (end <= 0) + end = 0; + if (_periodCount < MAX_C) + _out.write(" - "); + _out.write(link(_stat, _showEvents, _periodCount, end, _width, _height)); + _out.write(_("Next interval")); + _out.write(" "); + } + + _out.write("
"); + _out.write(link(_stat, !_showEvents, _periodCount, _end, _width, _height)); + _out.write(_showEvents ? _("Plot averages") : _("plot events")); + _out.write(""); + + _out.write("

" + _("All times are UTC.") + "

\n"); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + return ""; + } + + /** @since 0.9 */ + private static String link(String stat, boolean showEvents, + int periodCount, int end, + int width, int height) { + return + ""; + } + private static final int[] times = { 60, 2*60, 5*60, 10*60, 30*60, 60*60, -1 }; public String getForm() { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java index d7b0077a9c..4d740e4b5b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java @@ -172,32 +172,37 @@ public class StatSummarizer implements Runnable { public boolean renderPng(Rate rate, OutputStream out) throws IOException { return renderPng(rate, out, GraphHelper.DEFAULT_X, GraphHelper.DEFAULT_Y, - false, false, false, false, -1, true); + false, false, false, false, -1, 0, true); } /** * This does the single data graphs. * For the two-data bandwidth graph see renderRatePng(). * Synchronized to conserve memory. + * + * @param end number of periods before now * @return success */ public boolean renderPng(Rate rate, OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, - boolean showCredit) throws IOException { + int end, boolean showCredit) throws IOException { try { try { _sem.acquire(); } catch (InterruptedException ie) {} return locked_renderPng(rate, out, width, height, hideLegend, hideGrid, hideTitle, showEvents, - periodCount, showCredit); + periodCount, end, showCredit); } finally { _sem.release(); } } + /** + * @param end number of periods before now + */ private boolean locked_renderPng(Rate rate, OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, - boolean showCredit) throws IOException { + int end, boolean showCredit) throws IOException { if (width > GraphHelper.MAX_X) width = GraphHelper.MAX_X; else if (width <= 0) @@ -206,9 +211,11 @@ public class StatSummarizer implements Runnable { height = GraphHelper.MAX_Y; else if (height <= 0) height = GraphHelper.DEFAULT_Y; + if (end < 0) + end = 0; for (SummaryListener lsnr : _listeners) { if (lsnr.getRate().equals(rate)) { - lsnr.renderPng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); + lsnr.renderPng(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); return true; } } @@ -368,7 +375,7 @@ public class StatSummarizer implements Runnable { * @param specs statName.period,statName.period,statName.period * @return list of Rate objects */ - private List parseSpecs(String specs) { + List parseSpecs(String specs) { StringTokenizer tok = new StringTokenizer(specs, ","); List rv = new ArrayList(); while (tok.hasMoreTokens()) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index 1ea872a880..39290a0422 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -55,7 +55,7 @@ class SummaryListener implements RateSummaryListener { static final int PERIODS = 60 * 24; // 1440 private static final int MIN_ROWS = PERIODS; - private static final int MAX_ROWS = 91 * MIN_ROWS; + static final int MAX_ROWS = 91 * MIN_ROWS; private static final long THREE_MONTHS = 91l * 24 * 60 * 60 * 1000; public SummaryListener(Rate r) { @@ -191,10 +191,15 @@ class SummaryListener implements RateSummaryListener { _db = null; } - public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { + /** + * @param end number of periods before now + */ + public void renderPng(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, + boolean hideTitle, boolean showEvents, int periodCount, + int end, boolean showCredit) throws IOException { if (_renderer == null || _db == null) throw new IOException("No RRD, check logs for previous errors"); - _renderer.render(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); + _renderer.render(out, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); } public void renderPng(OutputStream out) throws IOException { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java index 02b4e51d38..35845f7c7c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java @@ -81,13 +81,21 @@ class SummaryRenderer { } public void render(OutputStream out) throws IOException { render(out, GraphHelper.DEFAULT_X, GraphHelper.DEFAULT_Y, - false, false, false, false, -1, false); } + false, false, false, false, -1, 0, false); } - public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, boolean hideTitle, boolean showEvents, int periodCount, boolean showCredit) throws IOException { + /** + * @param endp number of periods before now + */ + public void render(OutputStream out, int width, int height, boolean hideLegend, boolean hideGrid, + boolean hideTitle, boolean showEvents, int periodCount, + int endp, boolean showCredit) throws IOException { long end = _listener.now() - 75*1000; + long period = _listener.getRate().getPeriod(); + if (endp > 0) + end -= period * endp; if (periodCount <= 0 || periodCount > _listener.getRows()) periodCount = _listener.getRows(); - long start = end - _listener.getRate().getPeriod()*periodCount; + long start = end - (period * periodCount); //long begin = System.currentTimeMillis(); try { RrdGraphDef def = new RrdGraphDef(); @@ -103,9 +111,9 @@ class SummaryRenderer { String p; // we want the formatting and translation of formatDuration2(), except not zh, and not the   if (IS_WIN && "zh".equals(Messages.getLanguage(_context))) - p = DataHelper.formatDuration(_listener.getRate().getPeriod()); + p = DataHelper.formatDuration(period); else - p = DataHelper.formatDuration2(_listener.getRate().getPeriod()).replace(" ", " "); + p = DataHelper.formatDuration2(period).replace(" ", " "); if (showEvents) title = name + ' ' + _("events in {0}", p); else diff --git a/apps/routerconsole/jsp/graph.jsp b/apps/routerconsole/jsp/graph.jsp new file mode 100644 index 0000000000..6147fd96d0 --- /dev/null +++ b/apps/routerconsole/jsp/graph.jsp @@ -0,0 +1,22 @@ +<%@page contentType="text/html"%> +<%@page pageEncoding="UTF-8"%> + + + +<%@include file="css.jsi" %> +<%=intl.title("graphs")%> + + " /> +<% /* GraphHelper sets the defaults in setContextId, so setting the properties must be after the context */ %> + +<% + graphHelper.storeWriter(out); +%> + +<%@include file="summary.jsi" %> +

<%=intl._("I2P Performance Graphs")%>

+
+
+
+ +
diff --git a/apps/routerconsole/jsp/graphs.jsp b/apps/routerconsole/jsp/graphs.jsp index e54133250a..24dd94185d 100644 --- a/apps/routerconsole/jsp/graphs.jsp +++ b/apps/routerconsole/jsp/graphs.jsp @@ -6,7 +6,6 @@ <%@include file="css.jsi" %> <%=intl.title("graphs")%> - <% graphHelper.storeMethod(request.getMethod()); %> " /> <% /* GraphHelper sets the defaults in setContextId, so setting the properties must be after the context */ %> diff --git a/apps/routerconsole/jsp/viewstat.jsp b/apps/routerconsole/jsp/viewstat.jsp index ef5f1140fe..af7b2944cd 100644 --- a/apps/routerconsole/jsp/viewstat.jsp +++ b/apps/routerconsole/jsp/viewstat.jsp @@ -47,12 +47,15 @@ if ( !rendered && ((rs != null) || fakeBw) ) { int width = -1; int height = -1; int periodCount = -1; + int end = 0; String str = request.getParameter("width"); if (str != null) try { width = Integer.parseInt(str); } catch (NumberFormatException nfe) {} str = request.getParameter("height"); if (str != null) try { height = Integer.parseInt(str); } catch (NumberFormatException nfe) {} str = request.getParameter("periodCount"); if (str != null) try { periodCount = Integer.parseInt(str); } catch (NumberFormatException nfe) {} + str = request.getParameter("end"); + if (str != null) try { end = Integer.parseInt(str); } catch (NumberFormatException nfe) {} boolean hideLegend = Boolean.valueOf(""+request.getParameter("hideLegend")).booleanValue(); boolean hideGrid = Boolean.valueOf(""+request.getParameter("hideGrid")).booleanValue(); boolean hideTitle = Boolean.valueOf(""+request.getParameter("hideTitle")).booleanValue(); @@ -63,7 +66,7 @@ if ( !rendered && ((rs != null) || fakeBw) ) { if (fakeBw) rendered = net.i2p.router.web.StatSummarizer.instance().renderRatePng(cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); else - rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, showCredit); + rendered = net.i2p.router.web.StatSummarizer.instance().renderPng(rate, cout, width, height, hideLegend, hideGrid, hideTitle, showEvents, periodCount, end, showCredit); } if (rendered) cout.close(); From 6ee9b79e4576e2d1bca25b512caf1290937d0581 Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 26 Feb 2012 21:13:06 +0000 Subject: [PATCH 15/44] generics, final --- .../i2p/client/RequestLeaseSetMessageHandler.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java b/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java index 663c01b7bb..6bacb95f22 100644 --- a/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java +++ b/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java @@ -34,7 +34,7 @@ import net.i2p.util.Log; * @author jrandom */ class RequestLeaseSetMessageHandler extends HandlerImpl { - private final Map _existingLeaseSets; + private final Map _existingLeaseSets; public RequestLeaseSetMessageHandler(I2PAppContext context) { super(context, RequestLeaseSetMessage.MESSAGE_TYPE); @@ -59,7 +59,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { leaseSet.setDestination(session.getMyDestination()); // reuse the old keys for the client - LeaseInfo li = (LeaseInfo) _existingLeaseSets.get(session.getMyDestination()); + LeaseInfo li = _existingLeaseSets.get(session.getMyDestination()); if (li == null) { li = new LeaseInfo(session.getMyDestination()); _existingLeaseSets.put(session.getMyDestination(), li); @@ -98,11 +98,11 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { } private static class LeaseInfo { - private PublicKey _pubKey; - private PrivateKey _privKey; - private SigningPublicKey _signingPubKey; - private SigningPrivateKey _signingPrivKey; - private Destination _dest; + private final PublicKey _pubKey; + private final PrivateKey _privKey; + private final SigningPublicKey _signingPubKey; + private final SigningPrivateKey _signingPrivKey; + private final Destination _dest; public LeaseInfo(Destination dest) { _dest = dest; From 394943c36f74b685049b0f8d424e709ae2592e8c Mon Sep 17 00:00:00 2001 From: zzz Date: Sun, 26 Feb 2012 21:15:31 +0000 Subject: [PATCH 16/44] debug output of LS encryption key to correlate with SKM debug page --- .../java/src/net/i2p/router/web/NetDbRenderer.java | 10 +++++++--- .../src/net/i2p/crypto/TransientSessionKeyManager.java | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) 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 6b54c2988e..ebdacbfd69 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -106,7 +106,10 @@ public class NetDbRenderer { StringBuilder buf = new StringBuilder(4*1024); buf.append("

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

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

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

\n"); + buf.append("

").append(_("LeaseSets")); + if (debug) + buf.append(" - Debug mode - Sorted by hash distance, closest first"); + buf.append("

\n"); Hash ourRKey; Set leases; DecimalFormat fmt; @@ -169,9 +172,10 @@ public class NetDbRenderer { if (c++ == medianCount) median = dist; } - buf.append(" Dist: ").append(fmt.format(biLog2(dist))).append(""); - buf.append(" RKey: ").append(ls.getRoutingKey().toBase64()); + buf.append(" Dist: ").append(fmt.format(biLog2(dist))).append("
"); + buf.append("Routing Key: ").append(ls.getRoutingKey().toBase64()); buf.append("
"); + buf.append("Encryption Key: ").append(ls.getEncryptionKey().toBase64().substring(0, 20)).append("...
"); } for (int i = 0; i < ls.getLeaseCount(); i++) { buf.append(_("Lease")).append(' ').append(i + 1).append(": " + _("Gateway") + ' '); diff --git a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java index e17802042b..7959c68e93 100644 --- a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java @@ -625,7 +625,7 @@ public class TransientSessionKeyManager extends SessionKeyManager { OutboundSession sess = iter.next(); Set sets = new TreeSet(new TagSetComparator()); sets.addAll(sess.getTagSets()); - buf.append("
Target key: ").append(sess.getTarget().toBase64().substring(0, 64)).append("
" + + buf.append("
Target public key: ").append(sess.getTarget().toBase64().substring(0, 20)).append("...
" + "Established: ").append(DataHelper.formatDuration(now - sess.getEstablishedDate())).append(" ago
" + "Last Used: ").append(DataHelper.formatDuration(now - sess.getLastUsedDate())).append(" ago
" + "Session key: ").append(sess.getCurrentKey().toBase64()).append("
" + - ""); + ""); // jars added in wrapper.config URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader(); @@ -95,7 +96,9 @@ public class FileDumpHelper extends HelperBase { buf.append((new Date(mod)).toString()); else buf.append("Not found"); - buf.append("" + "" + "\n" + - " + if (statshelper.getCurrentIsLogged()) { %>checked="checked" <% } %> > <% } // shouldShowLog @@ -130,7 +130,7 @@ Warning - Log with care, stat file grows without limit.
%>
+ if (statshelper.getCurrentIsGraphed()) { %>checked="checked" <% } %> ><% } %> <% } // end iterating over all stats diff --git a/apps/susidns/src/jsp/addressbook.jsp b/apps/susidns/src/jsp/addressbook.jsp index 4736a4dc01..12d56987e3 100644 --- a/apps/susidns/src/jsp/addressbook.jsp +++ b/apps/susidns/src/jsp/addressbook.jsp @@ -42,7 +42,7 @@ - + ${book.book} <%=intl._("address book")%> - susidns @@ -158,7 +158,7 @@ ${book.loadBookMessages} - +
FileSizeDateSHA 256RevisionJDKBuiltMods
JDKBuiltByMods
"); + buf.append(""); + if (mod > 0 && !FileUtil.verifyZip(f)) + buf.append("CORRUPT
"); byte[] hash = sha256(f); if (hash != null) { byte[] hh = new byte[16]; @@ -132,6 +135,10 @@ public class FileDumpHelper extends HelperBase { buf.append(s); buf.append("
"); s = getAtt(att, "Build-Date"); + if (s != null) + buf.append(s); + buf.append(""); + s = getAtt(att, "Built-By"); if (s != null) buf.append(s); buf.append(""); diff --git a/apps/sam/java/build.xml b/apps/sam/java/build.xml index 849fbd55d7..076c2e4533 100644 --- a/apps/sam/java/build.xml +++ b/apps/sam/java/build.xml @@ -72,6 +72,7 @@ + @@ -87,6 +88,7 @@ + diff --git a/apps/streaming/java/build.xml b/apps/streaming/java/build.xml index 5f278f307c..971ae21cf2 100644 --- a/apps/streaming/java/build.xml +++ b/apps/streaming/java/build.xml @@ -64,6 +64,7 @@ + diff --git a/apps/susidns/src/build.xml b/apps/susidns/src/build.xml index 3fff55a34c..49a1629c35 100644 --- a/apps/susidns/src/build.xml +++ b/apps/susidns/src/build.xml @@ -98,6 +98,7 @@ + diff --git a/apps/susimail/build.xml b/apps/susimail/build.xml index 3368283d11..3e22444d89 100644 --- a/apps/susimail/build.xml +++ b/apps/susimail/build.xml @@ -46,6 +46,7 @@ basedir="src/" excludes="WEB-INF/web.xml LICENSE src/**/*"> + diff --git a/apps/systray/java/build.xml b/apps/systray/java/build.xml index 5baf4ab622..eeec392303 100644 --- a/apps/systray/java/build.xml +++ b/apps/systray/java/build.xml @@ -45,6 +45,7 @@ + diff --git a/build.properties b/build.properties index f3ead75765..ab2fa1b991 100644 --- a/build.properties +++ b/build.properties @@ -16,3 +16,5 @@ wrapperdocs.url=http://wrapper.tanukisoftware.com/jdoc/ # these are only for unit test javadocs i2pdocs.url=http://docs.i2p-projekt.de/javadoc/ junitdocs.url=http://junit.org/apidocs/ +# This will go in the jar manifests +build.built-by=unknown diff --git a/build.xml b/build.xml index 9c9105e748..150db9b859 100644 --- a/build.xml +++ b/build.xml @@ -166,6 +166,7 @@ + @@ -241,6 +242,7 @@ + @@ -291,6 +293,7 @@ + @@ -304,6 +307,7 @@ + @@ -318,6 +322,7 @@ + @@ -331,6 +336,7 @@ + @@ -344,6 +350,7 @@ + @@ -357,6 +364,7 @@ + @@ -370,6 +378,7 @@ + @@ -1120,6 +1129,7 @@ + @@ -1128,6 +1138,7 @@ + @@ -1136,6 +1147,7 @@ + @@ -1235,6 +1247,7 @@ + @@ -1243,6 +1256,7 @@ + @@ -1251,6 +1265,7 @@ + diff --git a/core/java/build.xml b/core/java/build.xml index c3eaf5c078..dad75fc9b5 100644 --- a/core/java/build.xml +++ b/core/java/build.xml @@ -59,6 +59,7 @@ + diff --git a/router/java/build.xml b/router/java/build.xml index e933086cf8..990b3e4732 100644 --- a/router/java/build.xml +++ b/router/java/build.xml @@ -73,6 +73,7 @@ + From e7bcff5e71911022c97fc262bd8baf4d14090b5b Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 1 Mar 2012 18:39:07 +0000 Subject: [PATCH 33/44] - Refactoring to use Jave URI parser to better handle escapes, IPv6 addresses, ports - Rewrite i2paddresshelper scanning/removal intermediate checkin, bug fixes to follow --- .../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 577 +++++++++++------- .../localServer/LocalHTTPServer.java | 19 +- 2 files changed, 374 insertions(+), 222 deletions(-) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 4980425c69..408c736f94 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -13,6 +13,8 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.net.Socket; import java.net.SocketException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -61,6 +63,10 @@ import net.i2p.util.Translate; * in browsers or other user-visible applications, as relative links will not * resolve correctly, cookies won't work, etc. * + * Note that http://$b64key/... and http://$b64key.i2p/... are NOT supported, as + * a b64 key may contain '=' and '~', both of which are illegal host name characters. + * Rewrite as http://i2p/$b64key/... + * * If the $site resolves with the I2P naming service, then it is directed towards * that eepsite, otherwise it is directed towards this client's outproxy (typically * "squid.i2p"). Only HTTP is supported (no HTTPS, ftp, mailto, etc). Both GET @@ -309,6 +315,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn return rv; } + private static final String HELPER_PARAM = "i2paddresshelper"; public static final String LOCAL_SERVER = "proxy.i2p"; private static final boolean DEFAULT_GZIP = true; /** all default to false */ @@ -321,11 +328,19 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn protected void clientConnectionRun(Socket s) { InputStream in = null; OutputStream out = null; + + /** + * The URL after fixup, always starting with http:// + */ String targetRequest = null; + boolean usingWWWProxy = false; boolean usingInternalServer = false; + String internalPath = null; + String internalRawQuery = null; String currentProxy = null; long requestId = ++__requestId; + try { out = s.getOutputStream(); InputReader reader = new InputReader(s.getInputStream()); @@ -351,79 +366,84 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix(requestId) + "First line [" + line + "]"); - int pos = line.indexOf(" "); - if (pos == -1) break; - method = line.substring(0, pos); - // TODO use Java URL class to make all this simpler and more robust - // That will also fix IPV6 [a:b:c] - String request = line.substring(pos + 1); + String[] params = line.split(" ", 3); + if (params.length != 3) + break; + String request = params[1]; + + // various obscure fixups if (request.startsWith("/") && getTunnel().getClientOptions().getProperty("i2ptunnel.noproxy") != null) { // what is this for ??? request = "http://i2p" + request; } else if (request.startsWith("/eepproxy/")) { - // /eepproxy/foo.i2p/bar/baz.html HTTP/1.0 + // Deprecated + // /eepproxy/foo.i2p/bar/baz.html String subRequest = request.substring("/eepproxy/".length()); - int protopos = subRequest.indexOf(" "); - String uri = subRequest.substring(0, protopos); - if (uri.indexOf("/") == -1) { - uri = uri + "/"; - } - // "http://" + "foo.i2p/bar/baz.html" + " HTTP/1.0" - request = "http://" + uri + subRequest.substring(protopos); + if (subRequest.indexOf("/") == -1) + subRequest += "/"; + request = "http://" + subRequest; + /**** } else if (request.toLowerCase(Locale.US).startsWith("http://i2p/")) { - // http://i2p/b64key/bar/baz.html HTTP/1.0 + // http://i2p/b64key/bar/baz.html + // we can't do this now by setting the URI host to the b64key, as + // it probably contains '=' and '~' which are illegal, + // and a host may not include escaped octets + // This will get undone below. String subRequest = request.substring("http://i2p/".length()); - int protopos = subRequest.indexOf(" "); - String uri = subRequest.substring(0, protopos); - if (uri.indexOf("/") == -1) { - uri = uri + "/"; - } - // "http://" + "b64key/bar/baz.html" + " HTTP/1.0" - request = "http://" + uri + subRequest.substring(protopos); + if (subRequest.indexOf("/") == -1) + subRequest += "/"; + "http://" + "b64key/bar/baz.html" + request = "http://" + subRequest; + } else if (request.toLowerCase(Locale.US).startsWith("http://")) { + // Unsupported + // http://$b64key/... + // This probably used to work, rewrite it so that + // we can create a URI without illegal characters + // This will get undone below. + String oldPath = request.substring(7); + int slash = oldPath.indexOf("/"); + if (slash < 0) + slash = oldPath.length(); + if (slash >= 516 && !oldPath.substring(0, slash).contains(".")) + request = "http://i2p/" + oldPath; + ****/ } - pos = request.indexOf("//"); - if (pos == -1) { + // Now use the Java URI parser + // This will be the incoming URI but will then get modified + // to be the outgoing URI (with http:// if going to outproxy, otherwise without) + URI requestURI; + try { + requestURI = new URI(request); + if (requestURI.getRawUserInfo() != null || requestURI.getRawFragment() != null) { + // these should never be sent to the proxy in the request line + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Removing userinfo or fragment [" + request + "]"); + requestURI = changeURI(requestURI, null, 0, null); + } + if (requestURI.getPath() == null || requestURI.getPath().length() <= 0) { + // Add a path + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Adding / path to [" + request + "]"); + requestURI = changeURI(requestURI, null, 0, "/"); + } + } catch (URISyntaxException use) { + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Bad request [" + request + "]", use); + break; + } + method = params[0]; + String protocolVersion = params[2]; + + protocol = requestURI.getScheme(); + host = requestURI.getHost(); + if (protocol == null || host == null) { + _log.warn(request); method = null; break; } - protocol = request.substring(0, pos + 2); - request = request.substring(pos + 2); - // "foo.i2p/bar/baz HTTP/1.1", with any i2paddresshelper parameter removed - targetRequest = request; - - // pos is the start of the path - pos = request.indexOf("/"); - if (pos == -1) { - //pos = request.length(); - method = null; - break; - } - host = request.substring(0, pos); - - // parse port - int posPort = host.indexOf(":"); - int port = 80; - if(posPort != -1) { - String[] parts = host.split(":"); - try { - host = parts[0]; - } catch (ArrayIndexOutOfBoundsException ex) { - if (out != null) { - out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); - writeFooter(out); - } - s.close(); - return; - - } - try { - port = Integer.parseInt(parts[1]); - } catch(Exception exc) { - // TODO: log this - } - } + int port = requestURI.getPort(); // Go through the various types of host names, set // the host and destination variables accordingly, @@ -433,115 +453,141 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // in our addressbook (all naming is local), // and it is removed from the request line. - if (host.length() >= 516 && host.indexOf(".") < 0) { - // http://b64key/bar/baz.html - destination = host; - host = getHostName(destination); - line = method + ' ' + request.substring(pos); - } else if (host.toLowerCase(Locale.US).equals(LOCAL_SERVER)) { + String hostLowerCase = host.toLowerCase(Locale.US); + if (hostLowerCase.equals(LOCAL_SERVER)) { // so we don't do any naming service lookups destination = host; usingInternalServer = true; - } else if (host.toLowerCase(Locale.US).endsWith(".i2p")) { + internalPath = requestURI.getPath(); + internalRawQuery = requestURI.getRawQuery(); + } else if (hostLowerCase.equals("i2p")) { + // pull the b64 dest out of the first path element + String oldPath = requestURI.getPath().substring(1); + int slash = oldPath.indexOf("/"); + if (slash < 0) { + slash = oldPath.length(); + oldPath += "/"; + } + String dest = oldPath.substring(0, slash); + if (slash >= 516 && !dest.contains(".")) { + // possible alternative: + // redirect to b32 + destination = dest; + host = getHostName(destination); + targetRequest = requestURI.toASCIIString(); + String newPath = dest.substring(slash); + String newURI = requestURI.getRawPath(); + String query = requestURI.getRawQuery(); + if (query != null) + newURI += '?' + query; + try { + requestURI = new URI(newURI); + } catch (URISyntaxException use) { + // shouldnt happen + _log.warn(request, use); + method = null; + break; + } + } else { + _log.warn(request); + host = null; + break; + } + } else if (hostLowerCase.endsWith(".i2p")) { // Destination gets the host name destination = host; // Host becomes the destination's "{b32}.b32.i2p" string, or "i2p" on lookup failure host = getHostName(destination); - int pos2; - if ((pos2 = request.indexOf("?")) != -1) { - // Try to find an address helper in the fragments - // and split the request into it's component parts for rebuilding later + if (requestURI.getPort() >= 0) { + // TODO support I2P ports someday + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Removing port from [" + request + "]"); + try { + requestURI = changeURI(requestURI, null, -1, null); + } catch (URISyntaxException use) { + _log.warn(request, use); + method = null; + break; + } + } + + String query = requestURI.getRawQuery(); + if (query != null) { boolean ahelperConflict = false; - String fragments = request.substring(pos2 + 1); - String uriPath = request.substring(0, pos2); - pos2 = fragments.indexOf(" "); - String protocolVersion = fragments.substring(pos2 + 1); - String urlEncoding = ""; - fragments = fragments.substring(0, pos2); - String initialFragments = fragments; - // FIXME split on ';' also - fragments = fragments + "&"; - String fragment; - while(fragments.length() > 0) { - pos2 = fragments.indexOf("&"); - fragment = fragments.substring(0, pos2); - fragments = fragments.substring(pos2 + 1); + // Try to find an address helper in the query + String[] helperStrings = removeHelper(query); + if (helperStrings != null && + !Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) { + query = helperStrings[0]; + if (query.equals("")) + query = null; + try { + requestURI = replaceQuery(requestURI, query); + } catch (URISyntaxException use) { + // shouldn't happen + _log.warn(request, use); + method = null; + break; + } + ahelperKey = helperStrings[1]; + // Key contains data, lets not ignore it + if (ahelperKey.length() > 0) { + if(ahelperKey.endsWith(".i2p")) { + // allow i2paddresshelper=.b32.i2p syntax. + /* + also i2paddresshelper=name.i2p for aliases + i.e. on your eepsite put + This is the name I want to be called. + */ + Destination dest = _context.namingService().lookup(ahelperKey); + if(dest==null) { + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Could not find destination for "+ahelperKey); + byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND); + out.write(header); + out.write(("

" + _("This seems to be a bad destination:") + " " + ahelperKey + " " + _("i2paddresshelper cannot help you with a destination like that!") + "

").getBytes("UTF-8")); + writeFooter(out); + // XXX: should closeSocket(s) be in a finally block? + closeSocket(s); + return; + } + ahelperKey = dest.toBase64(); + } - // Fragment looks like addresshelper key - if (fragment.startsWith("i2paddresshelper=") && - !Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) { - pos2 = fragment.indexOf("="); - ahelperKey = fragment.substring(pos2 + 1); - // Key contains data, lets not ignore it - if (ahelperKey != null) { - if(ahelperKey.endsWith(".i2p")) { - // allow i2paddresshelper=.b32.i2p syntax. - /* - also i2paddresshelper=name.i2p for aliases - i.e. on your eepsite put - This is the name I want to be called. - */ - Destination dest = _context.namingService().lookup(ahelperKey); - if(dest==null) { - if (_log.shouldLog(Log.WARN)) - _log.warn(getPrefix(requestId) + "Could not find destination for "+ahelperKey); - byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND); - out.write(header); - out.write(("

" + _("This seems to be a bad destination:") + " " + ahelperKey + " " + _("i2paddresshelper cannot help you with a destination like that!") + "

").getBytes("UTF-8")); - writeFooter(out); - // XXX: should closeSocket(s) be in a finally block? - closeSocket(s); - return; - } - ahelperKey = dest.toBase64(); - } - - ahelperPresent = true; - // ahelperKey will be validated later - if (host == null || "i2p".equals(host)) { - // Host lookup failed - resolvable only with addresshelper - // Store in local HashMap unless there is conflict - String old = addressHelpers.putIfAbsent(destination.toLowerCase(Locale.US), ahelperKey); - ahelperNew = old == null; - if ((!ahelperNew) && !old.equals(ahelperKey)) { + ahelperPresent = true; + // ahelperKey will be validated later + if (host == null || "i2p".equals(host)) { + // Host lookup failed - resolvable only with addresshelper + // Store in local HashMap unless there is conflict + String old = addressHelpers.putIfAbsent(destination.toLowerCase(Locale.US), ahelperKey); + ahelperNew = old == null; + if ((!ahelperNew) && !old.equals(ahelperKey)) { + // Conflict: handle when URL reconstruction done + ahelperConflict = true; + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + + "], trusted key [" + old + "], specified key [" + ahelperKey + "]."); + } + } else { + // If the host is resolvable from database, verify addresshelper key + // Silently bypass correct keys, otherwise alert + Destination hostDest = _context.namingService().lookup(destination); + if (hostDest != null) { + String destB64 = hostDest.toBase64(); + if (destB64 != null && !destB64.equals(ahelperKey)) { // Conflict: handle when URL reconstruction done ahelperConflict = true; if (_log.shouldLog(Log.WARN)) _log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + - "], trusted key [" + old + "], specified key [" + ahelperKey + "]."); - } - } else { - // If the host is resolvable from database, verify addresshelper key - // Silently bypass correct keys, otherwise alert - Destination hostDest = _context.namingService().lookup(destination); - if (hostDest != null) { - String destB64 = hostDest.toBase64(); - if (destB64 != null && !destB64.equals(ahelperKey)) { - // Conflict: handle when URL reconstruction done - ahelperConflict = true; - if (_log.shouldLog(Log.WARN)) - _log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + - "], trusted key [" + destB64 + "], specified key [" + ahelperKey + "]."); - - } + "], trusted key [" + destB64 + "], specified key [" + ahelperKey + "]."); + } } - } // ahelperKey - } else { - // Other fragments, just pass along - // Append each fragment to urlEncoding - if ("".equals(urlEncoding)) { - urlEncoding = "?" + fragment; - } else { - urlEncoding = urlEncoding + "&" + fragment; } - } - } - // Reconstruct the request minus the i2paddresshelper GET var - request = uriPath + urlEncoding + " " + protocolVersion; - targetRequest = request; + } // ahelperKey + } // helperstrings // Did addresshelper key conflict? if (ahelperConflict) { @@ -553,9 +599,17 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn byte[] header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN); writeErrorMessage(header, out, targetRequest, false, destination, null); } else { - String trustedURL = protocol + uriPath + urlEncoding; - // Fixme - any path is lost - String conflictURL = protocol + alias + '/' + urlEncoding; + String trustedURL = requestURI.toASCIIString(); + URI conflictURI; + try { + conflictURI = changeURI(requestURI, alias, 0, null); + } catch (URISyntaxException use) { + // shouldn't happen + _log.warn(request, use); + method = null; + break; + } + String conflictURL = conflictURI.toASCIIString(); byte[] header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT); out.write(header); out.write(_("To visit the destination in your host database, click here. To visit the conflicting addresshelper destination, click here.", trustedURL, conflictURL).getBytes("UTF-8")); @@ -572,11 +626,24 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (addressHelper != null) host = getHostName(addressHelper); - line = method + " " + request.substring(pos); + // now strip everything but path and query from URI + targetRequest = requestURI.toASCIIString(); + String newURI = requestURI.getRawPath(); + if (query != null) + newURI += '?' + query; + try { + requestURI = new URI(newURI); + } catch (URISyntaxException use) { + // shouldnt happen + _log.warn(request, use); + method = null; + break; + } + // end of (host endsWith(".i2p")) - } else if (host.toLowerCase(Locale.US).equals("localhost") || host.equals("127.0.0.1") || - host.startsWith("192.168.")) { + } else if (hostLowerCase.equals("localhost") || host.equals("127.0.0.1") || + host.startsWith("192.168.") || host.equals("[::1]")) { // if somebody is trying to get to 192.168.example.com, oh well if (out != null) { out.write(getErrorPage("localhost", ERR_LOCALHOST)); @@ -585,7 +652,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn s.close(); return; } else if (host.indexOf(".") != -1) { - // rebuild host host = host + ":" + port; // The request must be forwarded to a WWW proxy if (_log.shouldLog(Log.DEBUG)) @@ -606,37 +672,21 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn } destination = currentProxy; usingWWWProxy = true; + targetRequest = requestURI.toASCIIString(); if (_log.shouldLog(Log.DEBUG)) - _log.debug(getPrefix(requestId) + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!"); + _log.debug(getPrefix(requestId) + " [" + host + "]: wwwProxy!"); } else { // what is left for here? a hostname with no dots, and != "i2p" // and not a destination ??? // Perhaps something in privatehosts.txt ... - request = request.substring(pos + 1); - pos = request.indexOf("/"); - if (pos < 0) { - l.log("Invalid request url [" + request + "]"); - if (out != null) { - out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); - writeFooter(out); - } - s.close(); - return; - } - destination = request.substring(0, pos); + if (_log.shouldLog(Log.WARN)) + _log.warn("NODOTS, NOI2P: " + request); + destination = requestURI.getHost(); host = getHostName(destination); - line = method + " " + request.substring(pos); + targetRequest = requestURI.toASCIIString(); + // FIXME treat as I2P or not??? } // end host name processing - if (port != 80 && !usingWWWProxy) { - if (out != null) { - out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); - writeFooter(out); - } - s.close(); - return; - } - boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol); if (!isValid) { if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "notValid(" + host + ")"); @@ -645,18 +695,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn break; } - // don't do this, it forces yet another hostname lookup, - // and in all cases host was already set above - //if ((!usingWWWProxy) && (!usingInternalServer)) { - // String oldhost = host; - // host = getHostName(destination); // hide original host - // if (_log.shouldLog(Log.INFO)) - // _log.info(getPrefix(requestId) + " oldhost " + oldhost + " newhost " + host + " dest " + destination); - //} + line = method + ' ' + requestURI.toASCIIString() + ' ' + protocolVersion; if (_log.shouldLog(Log.DEBUG)) { - _log.debug(getPrefix(requestId) + "METHOD: \"" + method + "\""); - _log.debug(getPrefix(requestId) + "PROTOC: \"" + protocol + "\""); + _log.debug(getPrefix(requestId) + "NEWREQ: \"" + line + "\""); _log.debug(getPrefix(requestId) + "HOST : \"" + host + "\""); _log.debug(getPrefix(requestId) + "DEST : \"" + destination + "\""); } @@ -763,7 +805,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (method == null || destination == null) { //l.log("No HTTP method found in the request."); if (out != null) { - if (protocol != null && "http://".equals(protocol.toLowerCase(Locale.US))) + if (protocol != null && "http".equals(protocol.toLowerCase(Locale.US))) out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); else out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL)); @@ -794,11 +836,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // Ignore all the headers if (usingInternalServer) { // disable the add form if address helper is disabled - if (targetRequest.startsWith(LOCAL_SERVER + "/add?") && + if (internalPath.equals("/add") && Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) { out.write(ERR_HELPER_DISABLED); } else { - LocalHTTPServer.serveLocalFile(out, method, targetRequest, _proxyNonce); + LocalHTTPServer.serveLocalFile(out, method, internalPath, internalRawQuery, _proxyNonce); } s.close(); return; @@ -865,7 +907,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (ahelperNew && "GET".equals(method) && (userAgent == null || !userAgent.startsWith("Wget")) && !Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_DISABLE_HELPER)).booleanValue()) { - writeHelperSaveForm(out, destination, ahelperKey, protocol + targetRequest); + writeHelperSaveForm(out, destination, ahelperKey, targetRequest); s.close(); return; } @@ -875,10 +917,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // This also prevents the not-found error page from looking bad // Syndie can't handle a redirect of a POST if (ahelperPresent && !"POST".equals(method)) { - String uri = protocol + targetRequest; - int spc = uri.indexOf(" "); - if (spc >= 0) - uri = uri.substring(0, spc); + String uri = targetRequest; if (_log.shouldLog(Log.DEBUG)) _log.debug("Auto redirecting to " + uri); out.write(("HTTP/1.1 301 Address Helper Accepted\r\n"+ @@ -928,10 +967,6 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn private void writeHelperSaveForm(OutputStream out, String destination, String ahelperKey, String targetRequest) throws IOException { if (out == null) return; - // strip HTTP/1.1 - int protopos = targetRequest.indexOf(" "); - if (protopos >= 0) - targetRequest = targetRequest.substring(0, protopos); byte[] header = getErrorPage("ahelper-new", ERR_AHELPER_NEW); out.write(header); out.write(("\n" + @@ -939,6 +974,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn "
" + _("Host") + "" + destination + "
\n" + "
"+ + // FIXME if there is a query remaining it is lost "
" + "" + "
\n
" + @@ -1094,15 +1130,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (out != null) { out.write(errMessage); if (targetRequest != null) { - int protopos = targetRequest.indexOf(" "); - String uri; - if (protopos >= 0) - uri = targetRequest.substring(0, protopos); - else - uri = targetRequest; - out.write("http://".getBytes()); + out.write("\">".getBytes()); out.write(uri.getBytes()); out.write("".getBytes()); if (usingWWWProxy) { @@ -1196,7 +1227,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn } } ****/ - return protocol.toLowerCase(Locale.US).equals("http://"); + return protocol.toLowerCase(Locale.US).equals("http"); } private final static byte[] ERR_HELPER_DISABLED = @@ -1206,6 +1237,128 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn "Address helpers disabled") .getBytes(); + /** + * Change various parts of the URI. + * String parameters are all non-encoded. + * + * Scheme always preserved. + * Userinfo always cleared. + * Host changed if non-null. + * Port changed if non-zero. + * Path changed if non-null. + * Query always preserved. + * Fragment always cleared. + * + * @since 0.9 + */ + private static URI changeURI(URI uri, String host, int port, String path) throws URISyntaxException { + return new URI(uri.getScheme(), + null, + host != null ? host : uri.getHost(), + port != 0 ? port : uri.getPort(), + path != null ? path : uri.getPath(), + // FIXME this breaks encoded =, & + uri.getQuery(), + null); + } + + /** + * Replace query in the URI. + * Userinfo cleared if uri contained a query. + * Fragment cleared if uri contained a query. + * + * @param query an ENCODED query, removed if null + * @since 0.9 + */ + private static URI replaceQuery(URI uri, String query) throws URISyntaxException { + URI rv = uri; + if (rv.getRawQuery() != null) { + rv = new URI(rv.getScheme(), + null, + uri.getHost(), + uri.getPort(), + uri.getPath(), + null, + null); + } + if (query != null) { + String newURI = rv.toASCIIString() + '?' + query; + rv = new URI(newURI); + } + return rv; + } + + /** + * Remove the address helper from an encoded query. + * + * @param query an ENCODED query, removed if null + * @return rv[0] is ENCODED query with helper removed, non-null but possibly empty; + * rv[1] is DECODED helper value, non-null but possibly empty; + * rv null if no helper present + * @since 0.9 + */ + private static String[] removeHelper(String query) { + int keystart = 0; + int valstart = -1; + String key = null; + for (int i = 0; i <= query.length(); i++) { + char c = i < query.length() ? query.charAt(i) : '&'; + if (c == ';' || c == '&') { + // end of key or value + if (valstart < 0) + key = query.substring(keystart, i); + String decodedKey = LocalHTTPServer.decode(key); + if (decodedKey.equals(HELPER_PARAM)) { + String newQuery = keystart > 0 ? query.substring(0, keystart - 1) : ""; + if (i < query.length() - 1) { + if (keystart > 0) + newQuery += query.substring(i); + else + newQuery += query.substring(i + 1); + } + String value = valstart >= 0 ? query.substring(valstart, i) : ""; + String helperValue = LocalHTTPServer.decode(value); + return new String[] { newQuery, helperValue }; + } + keystart = i + 1; + valstart = -1; + } else if (c == '=') { + // end of key + key = query.substring(keystart, i); + valstart = i + 1; + } + } + return null; + } + +/**** + private static String[] tests = { + "", "foo", "foo=bar", "&", "&=&", "===", "&&", + "i2paddresshelper=foo", + "i2paddresshelpe=foo", + "2paddresshelper=foo", + "i2paddresshelper=%66oo", + "%692paddresshelper=foo", + "i2paddresshelper=foo&a=b", + "a=b&i2paddresshelper=foo", + "a=b&i2paddresshelper&c=d", + "a=b&i2paddresshelper=foo&c=d", + "a=b;i2paddresshelper=foo;c=d", + "a=b&i2paddresshelper=foo&c" + }; + + public static void main(String[] args) { + for (int i = 0; i < tests.length; i++) { + String[] s = removeHelper(tests[i]); + if (s != null) + System.out.println("Test \"" + tests[i] + "\" q=\"" + s[0] + "\" h=\"" + s[1] + "\""); + else + System.out.println("Test \"" + tests[i] + "\" no match"); + } + } +****/ + + /** */ private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.web.messages"; /** lang in routerconsole.lang property, else current locale */ diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java index 0140b609cd..7c68c4e406 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/localServer/LocalHTTPServer.java @@ -67,12 +67,13 @@ public abstract class LocalHTTPServer { * uncaught vulnerabilities. * Restrict to the /themes/ directory for now. * - * @param targetRequest "proxy.i2p/themes/foo.png HTTP/1.1" + * @param targetRequest decoded path only, non-null + * @param query raw (encoded), may be null */ - public static void serveLocalFile(OutputStream out, String method, String targetRequest, String proxyNonce) { + public static void serveLocalFile(OutputStream out, String method, String targetRequest, String query, String proxyNonce) { //System.err.println("targetRequest: \"" + targetRequest + "\""); // a home page message for the curious... - if (targetRequest.startsWith(I2PTunnelHTTPClient.LOCAL_SERVER + "/ ")) { + if (targetRequest.equals("/")) { try { out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes()); out.flush(); @@ -80,12 +81,11 @@ public abstract class LocalHTTPServer { return; } if ((method.equals("GET") || method.equals("HEAD")) && - targetRequest.startsWith(I2PTunnelHTTPClient.LOCAL_SERVER + "/themes/") && + targetRequest.startsWith("/themes/") && !targetRequest.contains("..")) { - int space = targetRequest.indexOf(' '); String filename = null; try { - filename = targetRequest.substring(I2PTunnelHTTPClient.LOCAL_SERVER.length() + 8, space); // "/themes/".length + filename = targetRequest.substring(8); // "/themes/".length } catch (IndexOutOfBoundsException ioobe) { return; } @@ -118,10 +118,9 @@ public abstract class LocalHTTPServer { // Add to addressbook (form submit) // Parameters are url, host, dest, nonce, and master | router | private. // Do the add and redirect. - if (targetRequest.startsWith(I2PTunnelHTTPClient.LOCAL_SERVER + "/add?")) { - int spc = targetRequest.indexOf(' '); - String query = targetRequest.substring(I2PTunnelHTTPClient.LOCAL_SERVER.length() + 5, spc); // "/add?".length() + if (targetRequest.equals("/add")) { Map opts = new HashMap(8); + // this only works if all keys are followed by =value StringTokenizer tok = new StringTokenizer(query, "=&;"); while (tok.hasMoreTokens()) { String k = tok.nextToken(); @@ -207,7 +206,7 @@ public abstract class LocalHTTPServer { * Decode %xx encoding * @since 0.8.7 */ - private static String decode(String s) { + public static String decode(String s) { if (!s.contains("%")) return s; StringBuilder buf = new StringBuilder(s.length()); From 4a74bd0fe7c36509d44e86f996d90fdd855b1eb8 Mon Sep 17 00:00:00 2001 From: kytv Date: Thu, 1 Mar 2012 19:02:32 +0000 Subject: [PATCH 34/44] HTML fixes --- .../java/src/org/klomp/snark/web/I2PSnarkServlet.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 7f3839ec94..f80409ccd4 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1356,7 +1356,7 @@ public class I2PSnarkServlet extends Default { out.write(Integer.toString(times[i])); out.write("\""); if (times[i] == delay) - out.write(" selected=\"true\""); + out.write(" selected=\"selected\""); out.write(">"); if (times[i] > 0) out.write(DataHelper.formatDuration2(times[i] * 1000)); @@ -1379,15 +1379,15 @@ public class I2PSnarkServlet extends Default { /* out.write("Seed percentage:
\n"); @@ -1574,7 +1574,7 @@ public class I2PSnarkServlet extends Default { for (int i = min; i <= max; i++) { buf.append("\n"); From 5e5e4f6f2c943d0b5c7dd81abc23291f141b78e1 Mon Sep 17 00:00:00 2001 From: kytv Date: Thu, 1 Mar 2012 19:16:44 +0000 Subject: [PATCH 35/44] HTML fix --- apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java | 2 +- 1 file changed, 1 insertion(+), 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 f80409ccd4..0a9421a89d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1464,7 +1464,7 @@ public class I2PSnarkServlet extends Default { } out.write("
"); out.write(_("I2CP options")); - out.write(":
\n" + "
  Date: Thu, 1 Mar 2012 23:38:22 +0000 Subject: [PATCH 36/44] Fixes for: IPv6 addresses Reject all hostnames w/o dots except IPv6 http://i2p/b64dest Log tweaks Add nicer ahelper-notfound error page --- .../i2p/i2ptunnel/I2PTunnelHTTPClient.java | 38 ++++++++++++------- .../proxy/ahelper-notfound-header.ht | 23 +++++++++++ 2 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 installer/resources/proxy/ahelper-notfound-header.ht diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 408c736f94..ba47c5c37a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -108,7 +108,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn "That I2P Destination was not found. Perhaps you pasted in the "+ "wrong BASE64 I2P Destination or the link you are following is "+ "bad. The host (or the WWW proxy, if you're using one) could also "+ - "be temporarily offline. You may want to retry. "+ + "be temporarily offline. You may want to retry. "+ "Could not find the following Destination:

") .getBytes(); @@ -438,7 +438,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn protocol = requestURI.getScheme(); host = requestURI.getHost(); if (protocol == null || host == null) { - _log.warn(request); + _log.warn("Null protocol or host: " + request); method = null; break; } @@ -475,8 +475,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn destination = dest; host = getHostName(destination); targetRequest = requestURI.toASCIIString(); - String newPath = dest.substring(slash); - String newURI = requestURI.getRawPath(); + String newURI = oldPath.substring(slash); String query = requestURI.getRawQuery(); if (query != null) newURI += '?' + query; @@ -489,7 +488,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn break; } } else { - _log.warn(request); + _log.warn("Bad http://i2p/b64dest " + request); host = null; break; } @@ -501,6 +500,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn if (requestURI.getPort() >= 0) { // TODO support I2P ports someday + //if (port >= 0) + // host = host + ':' + port; if (_log.shouldLog(Log.WARN)) _log.warn(getPrefix(requestId) + "Removing port from [" + request + "]"); try { @@ -651,8 +652,9 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn } s.close(); return; - } else if (host.indexOf(".") != -1) { - host = host + ":" + port; + } else if (host.contains(".") || host.startsWith("[")) { + if (port >= 0) + host = host + ':' + port; // The request must be forwarded to a WWW proxy if (_log.shouldLog(Log.DEBUG)) _log.debug("Before selecting outproxy for " + host); @@ -679,12 +681,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn // what is left for here? a hostname with no dots, and != "i2p" // and not a destination ??? // Perhaps something in privatehosts.txt ... + // Rather than look it up, just bail out. if (_log.shouldLog(Log.WARN)) _log.warn("NODOTS, NOI2P: " + request); - destination = requestURI.getHost(); - host = getHostName(destination); - targetRequest = requestURI.toASCIIString(); - // FIXME treat as I2P or not??? + if (out != null) { + out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); + writeFooter(out); + } + s.close(); + return; } // end host name processing boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol); @@ -854,9 +859,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn String addressHelper = addressHelpers.get(destination.toLowerCase(Locale.US)); if (addressHelper != null) { clientDest = _context.namingService().lookup(addressHelper); - // remove bad entries - if (clientDest == null) + if (clientDest == null) { + // remove bad entries addressHelpers.remove(destination.toLowerCase(Locale.US)); + if (_log.shouldLog(Log.WARN)) + _log.warn(getPrefix(requestId) + "Could not find destination for " + addressHelper); + byte[] header = getErrorPage("ahelper-notfound", ERR_AHELPER_NOTFOUND); + writeErrorMessage(header, out, targetRequest, false, destination, null); + s.close(); + return; + } } else if ("i2p".equals(host)) { clientDest = null; } else if (destination.length() == 60 && destination.toLowerCase(Locale.US).endsWith(".b32.i2p")) { diff --git a/installer/resources/proxy/ahelper-notfound-header.ht b/installer/resources/proxy/ahelper-notfound-header.ht new file mode 100644 index 0000000000..0cdc36fb6d --- /dev/null +++ b/installer/resources/proxy/ahelper-notfound-header.ht @@ -0,0 +1,23 @@ +HTTP/1.1 409 Bad Helper +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + + +I2P Warning: Bad Address Helper + + + + + +
+

Warning: Bad Address Helper

+

+The helper key you put for i2paddresshelper= is not resolvable. +It seems to be garbage data, or a mistyped b32. Check your URL +to try and fix the helper key to be a valid Base 32 hostname or Base 64 key. +

From 75eda7e1b140d181bc35856071593536af759e17 Mon Sep 17 00:00:00 2001 From: zzz Date: Thu, 1 Mar 2012 23:52:56 +0000 Subject: [PATCH 37/44] log tweak --- .../src/net/i2p/client/streaming/ConnectionManager.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java index f50a4b5cc8..6e8811a2fe 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/ConnectionManager.java @@ -161,8 +161,7 @@ class ConnectionManager { // active++; //} if (locked_tooManyStreams()) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Refusing connection since we have exceeded our max of " + _log.logAlways(Log.WARN, "Refusing connection since we have exceeded our max of " + _maxConcurrentStreams + " connections"); reject = true; } else { @@ -233,8 +232,7 @@ class ConnectionManager { while (true) { long remaining = expiration - _context.clock().now(); if (remaining <= 0) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Refusing to connect since we have exceeded our max of " + _log.logAlways(Log.WARN, "Refusing to connect since we have exceeded our max of " + _maxConcurrentStreams + " connections"); _numWaiting--; return null; @@ -243,8 +241,7 @@ class ConnectionManager { if (locked_tooManyStreams()) { // allow a full buffer of pending/waiting streams if (_numWaiting > _maxConcurrentStreams) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Refusing connection since we have exceeded our max of " + _log.logAlways(Log.WARN, "Refusing connection since we have exceeded our max of " + _maxConcurrentStreams + " and there are " + _numWaiting + " waiting already"); _numWaiting--; From f62c3047b586c2df277e0332a19fdbcaeddc4f6a Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 2 Mar 2012 01:34:21 +0000 Subject: [PATCH 38/44] history for prop, -1 --- history.txt | 33 +++++++++++++++++++ .../src/net/i2p/router/RouterVersion.java | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/history.txt b/history.txt index e3b1aae098..c3290a434f 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,36 @@ +2012-03-02 zzz + * BlockfileNamingService: Add negative cache + * Build: Add built-by to jars; check for corrupt jars on debug page + * configstats.jsp: Hide log settings unless already enabled + * DataStructures: + - Remove static logs + - Sort addresses in RouterInfo at initialization only; + change from Set to List to save space + - Remove unused counters in Lease to save space + - Increase max leases to 16 + * Graphs: + - New single graph page with easy resizing + - Support graphing of previous intervals + * i2pinstall.exe: Add icon + * i2psnark: + - Add tracker configuration form + - Remove custom tracker option from create form + - Add private torrent option + - More icons in buttons + - Use js for refresh + * I2PTunnelHTTPClient: + - Refactoring to use Java URI parser to better handle + escapes, IPv6 addresses, ports + - Rewrite i2paddresshelper scanning/removal + - Refactor out local server code + - Nicer address helper error page + * NetDB: + - Reenable verify of RI stores, disabled in 0.7.9, + checkin comments claim reenabled in 0.7.10 but didn't happen. + - Synchronize StoreJob.sendNext() to avoid dups + * netdb.jsp: Fix debug leaseset count again + * susidns: Add b64 hash to details page + * 2012-02-27 0.8.13 released 2012-02-22 kytv diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index a411b00998..87e5bffca0 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 0; + public final static long BUILD = 1; /** for example "-test" */ public final static String EXTRA = ""; From 1aa24a38a498080d8f48667d90b2ac8078461055 Mon Sep 17 00:00:00 2001 From: kytv Date: Fri, 2 Mar 2012 18:46:34 +0000 Subject: [PATCH 39/44] Various HTML fixes --- .../java/src/org/klomp/snark/web/I2PSnarkServlet.java | 2 +- .../java/src/net/i2p/router/web/GraphHelper.java | 8 ++++---- .../java/src/net/i2p/router/web/TunnelRenderer.java | 3 ++- apps/routerconsole/jsp/configstats.jsp | 6 +++--- apps/susidns/src/jsp/addressbook.jsp | 6 +++--- apps/susidns/src/jsp/config.jsp | 2 +- apps/susidns/src/jsp/details.jsp | 4 ++-- apps/susidns/src/jsp/subscriptions.jsp | 2 +- .../src/net/i2p/router/transport/TransportManager.java | 6 +++--- 9 files changed, 20 insertions(+), 19 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 830b92b2a0..53c20b8f3b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1604,7 +1604,7 @@ public class I2PSnarkServlet extends Default { "
\n" + + "
\n" + "\n" + "\n" + // "\n" + 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 f31c7def56..b5d54b4112 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -341,8 +341,8 @@ public class GraphHelper extends FormHandler { "\n" + "\n"); _out.write(_("Periods") + ":
\n"); - _out.write(_("Plot averages") + ": "); - _out.write(_("or")+ " " +_("plot events") + ":
\n"); + _out.write(_("Plot averages") + ": "); + _out.write(_("or")+ " " +_("plot events") + ":
\n"); _out.write(_("Image sizes") + ": " + _("width") + ": " + _("pixels") + ", " + _("height") + ": " + _("pixels") + "
\n"); @@ -352,7 +352,7 @@ public class GraphHelper extends FormHandler { _out.write(Integer.toString(times[i])); _out.write("\""); if (times[i] == _refreshDelaySeconds) - _out.write(" selected=\"true\""); + _out.write(" selected=\"selected\""); _out.write(">"); if (times[i] > 0) _out.write(DataHelper.formatDuration2(times[i] * 1000)); @@ -365,7 +365,7 @@ public class GraphHelper extends FormHandler { " " + "
"); } catch (IOException ioe) { 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 73efe19de4..fdc670f534 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java @@ -134,6 +134,7 @@ public class TunnelRenderer { out.write("
" + _("Inactive participating tunnels") + ": " + inactive + "
\n"); out.write("
" + _("Lifetime bandwidth usage") + ": " + DataHelper.formatSize2(processed*1024) + "B
\n"); //renderPeers(out); + out.write(""); } private static class TunnelComparator implements Comparator { @@ -222,7 +223,7 @@ public class TunnelRenderer { } } if (live <= 0) - out.write("
" + _("No tunnels; waiting for the grace period to end.") + "
\n"); + out.write("
" + _("No tunnels; waiting for the grace period to end.") + "
\n"); out.write("
" + _("Lifetime bandwidth usage") + ": " + DataHelper.formatSize2(processedIn*1024) + "B " + _("in") + ", " + DataHelper.formatSize2(processedOut*1024) + "B " + _("out") + "
"); diff --git a/apps/routerconsole/jsp/configstats.jsp b/apps/routerconsole/jsp/configstats.jsp index 94cf968331..f284badae4 100644 --- a/apps/routerconsole/jsp/configstats.jsp +++ b/apps/routerconsole/jsp/configstats.jsp @@ -76,7 +76,7 @@ function toggleAll(category)

<%=intl._("Configure I2P Stat Collection")%>

<%=intl._("Enable full stats?")%> checked="true" <% } %> > + if (statshelper.getIsFull()) { %>checked="checked" <% } %> > (<%=intl._("change requires restart to take effect")%>)
<% @@ -122,7 +122,7 @@ Warning - Log with care, stat file grows without limit.
%>

checked="true" <% } %> > <% if (statshelper.getCurrentCanBeGraphed()) { %> checked="true" <% } %> ><% } %><%=statshelper.getCurrentStatName()%>:
<%=statshelper.getCurrentStatDescription()%>
"><%=intl._("details")%>
@@ -190,7 +190,7 @@ ${book.loadBookMessages}
<%=intl._("Host Name")%>
-<%=intl._("Destination")%> +<%=intl._("Destination")%>

" > diff --git a/apps/susidns/src/jsp/config.jsp b/apps/susidns/src/jsp/config.jsp index 23cce5adad..a94e693e54 100644 --- a/apps/susidns/src/jsp/config.jsp +++ b/apps/susidns/src/jsp/config.jsp @@ -38,7 +38,7 @@ - + <%=intl._("configuration")%> - susidns diff --git a/apps/susidns/src/jsp/details.jsp b/apps/susidns/src/jsp/details.jsp index 3d59c7dc1f..1f15b67d26 100644 --- a/apps/susidns/src/jsp/details.jsp +++ b/apps/susidns/src/jsp/details.jsp @@ -36,7 +36,7 @@ - + ${book.book} <%=intl._("addressbook")%> - susidns @@ -122,7 +122,7 @@ <%=addr.getNotes()%> <%=intl._("Destination")%> - +

diff --git a/apps/susidns/src/jsp/subscriptions.jsp b/apps/susidns/src/jsp/subscriptions.jsp index 8d1c6c2489..c01e2ee08e 100644 --- a/apps/susidns/src/jsp/subscriptions.jsp +++ b/apps/susidns/src/jsp/subscriptions.jsp @@ -38,7 +38,7 @@ - + <%=intl._("subscriptions")%> - susidns diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 8b6b29713d..d0a10f31b5 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -518,9 +518,9 @@ public class TransportManager implements TransportEventListener { buf.append("

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

" + "

").append(_("Peer")).append(": ").append(_("The remote peer, identified by router hash")).append("
\n" + "").append(_("Dir")).append(": " + - " ").append(_("Inbound connection")).append("
\n" + + "\"Inbound\" ").append(_("Inbound connection")).append("
\n" + "       " + - " ").append(_("Outbound connection")).append("
\n" + + "\"Outbound\" ").append(_("Outbound connection")).append("
\n" + "       " + "\"V\" ").append(_("They offered to introduce us (help other peers traverse our firewall)")).append("
\n" + "       " + @@ -531,7 +531,7 @@ public class TransportManager implements TransportEventListener { "").append(_("Skew")).append(": ").append(_("The difference between the peer's clock and your own")).append("
\n" + "CWND: ").append(_("The congestion window, which is how many bytes can be sent without an acknowledgement")).append(" /
\n" + "        ").append(_("The number of sent messages awaiting acknowledgement")).append(" /
\n" + - "        ").append(_("The maximum number of concurrent messages to send")).append(" /
\n"+ + "        ").append(_("The maximum number of concurrent messages to send")).append(" /
\n"+ "        ").append(_("The number of pending sends which exceed congestion window")).append("
\n" + "SST: ").append(_("The slow start threshold")).append("
\n" + "RTT: ").append(_("The round trip time in milliseconds")).append("
\n" + From 2bff0d6bcc4cf542cbc504d4ee64b805966507e8 Mon Sep 17 00:00:00 2001 From: kytv Date: Fri, 2 Mar 2012 22:32:45 +0000 Subject: [PATCH 40/44] HTML validation fixes --- .../org/klomp/snark/web/I2PSnarkServlet.java | 2 +- .../i2p/router/web/ConfigClientsHelper.java | 8 ++++---- .../i2p/router/web/ConfigLoggingHelper.java | 4 ++-- .../net/i2p/router/web/ConfigNetHelper.java | 6 +++--- .../i2p/router/web/ConfigReseedHelper.java | 4 ++-- .../i2p/router/web/ConfigTunnelsHelper.java | 6 +++--- .../net/i2p/router/web/ConfigUIHelper.java | 4 ++-- .../i2p/router/web/ConfigUpdateHelper.java | 16 +++++++-------- apps/routerconsole/jsp/configreseed.jsp | 2 +- apps/routerconsole/jsp/configupdate.jsp | 4 ++-- apps/susidns/src/jsp/addressbook.jsp | 4 ++-- apps/susidns/src/jsp/details.jsp | 2 +- router/java/src/net/i2p/router/Blocklist.java | 20 +++++++++---------- 13 files changed, 41 insertions(+), 41 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 53c20b8f3b..5e3aa5f2db 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -1554,7 +1554,7 @@ public class I2PSnarkServlet extends Default { } out.write(""); out.write(_("I2CP options")); - out.write(":
\n" + " "); // The icons were way too much, so there's an X in each button class, diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java index 6b86caeb22..ea8ec0aedc 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java @@ -80,7 +80,7 @@ public class ConfigLoggingHelper extends HelperBase { String l = levels[i]; buf.append("\n"); } @@ -121,7 +121,7 @@ public class ConfigLoggingHelper extends HelperBase { StringBuilder buf = new StringBuilder(65536); buf.append("" + _("Outbound options") + ":\n" + "").append(ngettext(DUMMY1 + name, DUMMY2 + name + 's', i)); buf.append("\n"); } 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 7acae19630..f5f16aebd2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java @@ -14,7 +14,7 @@ public class ConfigUIHelper extends HelperBase { for (String theme : themes) { buf.append("").append(_(theme)).append("
\n"); } return buf.toString(); @@ -73,7 +73,7 @@ public class ConfigUIHelper extends HelperBase { // we use "lang" so it is set automagically in CSSHelper buf.append("") .append("\"\" ") .append(_(xlangs[i])).append("
\n"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java index 88aaa70b20..8ef110c396 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java @@ -75,7 +75,7 @@ public class ConfigUpdateHelper extends HelperBase { public String getUpdateThroughProxy() { String proxy = _context.getProperty(ConfigUpdateHandler.PROP_SHOULD_PROXY, ConfigUpdateHandler.DEFAULT_SHOULD_PROXY); if (Boolean.valueOf(proxy).booleanValue()) - return ""; + return ""; else return ""; } @@ -83,7 +83,7 @@ public class ConfigUpdateHelper extends HelperBase { public String getUpdateUnsigned() { String foo = _context.getProperty(ConfigUpdateHandler.PROP_UPDATE_UNSIGNED); if (Boolean.valueOf(foo).booleanValue()) - return ""; + return ""; else return ""; } @@ -106,7 +106,7 @@ public class ConfigUpdateHelper extends HelperBase { for (int i = 0; i < PERIODS.length; i++) { buf.append("\n"); @@ -128,22 +128,22 @@ public class ConfigUpdateHelper extends HelperBase { buf.append(""); buf.append(""); if (_context.hasWrapper()) { buf.append(""); } diff --git a/apps/routerconsole/jsp/configreseed.jsp b/apps/routerconsole/jsp/configreseed.jsp index 648a14ee95..2a08d1015f 100644 --- a/apps/routerconsole/jsp/configreseed.jsp +++ b/apps/routerconsole/jsp/configreseed.jsp @@ -41,7 +41,7 @@ > <%=intl._("Use non-SSL only")%> <%=intl._("Reseed URLs")%>: - + <%=intl._("Enable HTTP Proxy?")%> > diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index c3066ade63..465f9b412e 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -56,9 +56,9 @@ " /> <% if (updatehelper.canInstall()) { %> <%=intl._("Update URLs")%>: - + <%=intl._("Trusted keys")%>: - + <%=intl._("Update with unsigned development builds?")%> <%=intl._("Unsigned Build URL")%>: diff --git a/apps/susidns/src/jsp/addressbook.jsp b/apps/susidns/src/jsp/addressbook.jsp index 12d56987e3..e0a5de3148 100644 --- a/apps/susidns/src/jsp/addressbook.jsp +++ b/apps/susidns/src/jsp/addressbook.jsp @@ -158,7 +158,7 @@ ${book.loadBookMessages}
"><%=intl._("details")%> - + @@ -190,7 +190,7 @@ ${book.loadBookMessages}
<%=intl._("Host Name")%>
-<%=intl._("Destination")%> +<%=intl._("Destination")%>

" > diff --git a/apps/susidns/src/jsp/details.jsp b/apps/susidns/src/jsp/details.jsp index 1f15b67d26..49a4b7b634 100644 --- a/apps/susidns/src/jsp/details.jsp +++ b/apps/susidns/src/jsp/details.jsp @@ -122,7 +122,7 @@ <%=addr.getNotes()%> <%=intl._("Destination")%> - +

diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index 48ff328a2c..10f9d51b3a 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -781,7 +781,7 @@ public class Blocklist { Set singles = new TreeSet(); singles.addAll(_singleIPBlocklist); if (!singles.isEmpty()) { - out.write("
"); + out.write(""); // first 0 - 127 @@ -789,27 +789,27 @@ public class Blocklist { int ip = ii.intValue(); if (ip < 0) continue; - out.write("\n"); + out.write("\n"); } // then 128 - 255 for (Integer ii : singles) { int ip = ii.intValue(); if (ip >= 0) break; - out.write("\n"); + out.write("\n"); } out.write("
"); out.write(_("IPs Banned Until Restart")); out.write("
"); + out.write("
"); out.write(toStr(ip)); - out.write(" 
 
"); + out.write("
"); out.write(toStr(ip)); - out.write(" 
 
"); } if (_blocklistSize > 0) { - out.write("
"); + out.write(""); int max = Math.min(_blocklistSize, MAX_DISPLAY); @@ -819,7 +819,7 @@ public class Blocklist { int from = getFrom(_blocklist[i]); if (from < 0) continue; - out.write("\n"); @@ -832,7 +832,7 @@ public class Blocklist { int from = getFrom(_blocklist[i]); if (from >= 0) break; - out.write("\n"); From 15e182809d2a4db6ebfce6fd86837a3ec3c34783 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 3 Mar 2012 18:19:50 +0000 Subject: [PATCH 41/44] html fix --- .../java/src/net/i2p/router/web/FileDumpHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java index 99026be16a..7bb1e99d05 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/FileDumpHelper.java @@ -145,7 +145,7 @@ public class FileDumpHelper extends HelperBase { s = getAtt(att, "Workspace-Changes"); if (s != null) buf.append(s.replace(",", "
")); - buf.append(""); + buf.append("\n"); } private static byte[] sha256(File f) { From a0f714097a23254b82d46d7d0e5de002704bedde Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 3 Mar 2012 18:20:06 +0000 Subject: [PATCH 42/44] css tweak --- installer/resources/themes/snark/ubergine/snark.css | 2 +- installer/resources/themes/snark/vanilla/snark.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/installer/resources/themes/snark/ubergine/snark.css b/installer/resources/themes/snark/ubergine/snark.css index ec7583decf..560a212209 100644 --- a/installer/resources/themes/snark/ubergine/snark.css +++ b/installer/resources/themes/snark/ubergine/snark.css @@ -470,7 +470,7 @@ input { border: 1px inset #000; background: #212 url('/themes/snark/ubergine/images/graytile.png'); color: #f60; - margin: 2px 0; + margin: 2px 4px; } input.r { diff --git a/installer/resources/themes/snark/vanilla/snark.css b/installer/resources/themes/snark/vanilla/snark.css index de8cba80fb..efd061582d 100644 --- a/installer/resources/themes/snark/vanilla/snark.css +++ b/installer/resources/themes/snark/vanilla/snark.css @@ -493,7 +493,7 @@ input { border: 1px inset #000; background: #fff /*url('/themes/snark/ubergine/images/graytile.png')*/; color: #000; - margin: 2px 0; + margin: 2px 4px; } input.r { From 0e8d3d18628ebf368da25f9f0049f60ceaacc4e3 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 3 Mar 2012 18:21:00 +0000 Subject: [PATCH 43/44] remove bw stats from netdb effective next release --- router/java/src/net/i2p/router/StatisticsManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/router/java/src/net/i2p/router/StatisticsManager.java b/router/java/src/net/i2p/router/StatisticsManager.java index 75dcd5ecd3..c943401257 100644 --- a/router/java/src/net/i2p/router/StatisticsManager.java +++ b/router/java/src/net/i2p/router/StatisticsManager.java @@ -85,7 +85,7 @@ public class StatisticsManager implements Service { if (_context.getBooleanPropertyDefaultTrue(PROP_PUBLISH_RANKINGS)) { long publishedUptime = _context.router().getUptime(); // Don't publish these for first hour - if (publishedUptime > 62*60*1000) + if (publishedUptime > 62*60*1000 && CoreVersion.VERSION.equals("0.8.13")) includeAverageThroughput(stats); //includeRate("router.invalidMessageTime", stats, new long[] { 10*60*1000 }); //includeRate("router.duplicateMessageId", stats, new long[] { 24*60*60*1000 }); From e2acc9fdd236b61851ad947feecad57b8e5dec99 Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 3 Mar 2012 18:58:31 +0000 Subject: [PATCH 44/44] * i2psnark: - CSS tweaks - Ajax fixes - Move js to console in prep for merging w/ homepage --- apps/i2psnark/java/build.xml | 6 +----- .../org/klomp/snark/web/I2PSnarkServlet.java | 18 +++++++++++++----- .../jsp/js/ajax.js} | 12 ++++-------- 3 files changed, 18 insertions(+), 18 deletions(-) rename apps/{i2psnark/js/i2psnark.js => routerconsole/jsp/js/ajax.js} (71%) diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index 3065ed9bc3..94dd809b6e 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -99,14 +99,10 @@ - - - - @@ -119,7 +115,7 @@ - + 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 5e3aa5f2db..24094515c5 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -158,6 +158,8 @@ public class I2PSnarkServlet extends Default { resp.setCharacterEncoding("UTF-8"); resp.setContentType("text/html; charset=UTF-8"); PrintWriter out = resp.getWriter(); + //if (_log.shouldLog(Log.DEBUG)) + // _manager.addMessage((_context.clock().now() / 1000) + " xhr1 p=" + req.getParameter("p")); writeMessages(out); writeTorrents(out, req); return; @@ -204,7 +206,8 @@ public class I2PSnarkServlet extends Default { String peerParam = req.getParameter("p"); String peerString; - if (peerParam == null || !_manager.util().connected()) { + if (peerParam == null || (!_manager.util().connected()) || + peerParam.replaceAll("[a-zA-Z0-9~=-]", "").length() > 0) { // XSS peerString = ""; } else { peerString = "?p=" + peerParam; @@ -223,15 +226,20 @@ public class I2PSnarkServlet extends Default { int delay = 0; if (!isConfigure) { delay = _manager.getRefreshDelaySeconds(); - if (delay > 0) + if (delay > 0) { //out.write("\n"); - out.write("\n"); + out.write("\n" + + "\n"); + } } out.write(HEADER_A + _themePath + HEADER_B + "\n"); if (isConfigure || delay <= 0) out.write(""); else - out.write(""); + out.write(""); out.write("
"); if (isConfigure) { out.write("
\n"); @@ -418,6 +425,7 @@ public class I2PSnarkServlet extends Default { out.write(" "); } out.write("\n"); + String uri = "/i2psnark/"; for (int i = 0; i < snarks.size(); i++) { Snark snark = (Snark)snarks.get(i); boolean showDebug = "2".equals(peerParam); diff --git a/apps/i2psnark/js/i2psnark.js b/apps/routerconsole/jsp/js/ajax.js similarity index 71% rename from apps/i2psnark/js/i2psnark.js rename to apps/routerconsole/jsp/js/ajax.js index ba0e3f9115..dab3164a09 100644 --- a/apps/i2psnark/js/i2psnark.js +++ b/apps/routerconsole/jsp/js/ajax.js @@ -1,9 +1,8 @@ -//var page = "home"; -function ajax(url,target) { +function ajax(url, target, refresh) { // native XMLHttpRequest object if (window.XMLHttpRequest) { req = new XMLHttpRequest(); - req.onreadystatechange = function() {ajaxDone(target);}; + req.onreadystatechange = function() {ajaxDone(url, target, refresh);}; req.open("GET", url, true); req.send(null); // IE/Windows ActiveX version @@ -15,10 +14,9 @@ function ajax(url,target) { req.send(null); } } - //setTimeout("ajax(page,'scriptoutput')", 5000); } -function ajaxDone(target) { +function ajaxDone(url, target, refresh) { // only if req is "loaded" if (req.readyState == 4) { // only if "OK" @@ -30,8 +28,6 @@ function ajaxDone(target) { document.getElementById(target).innerHTML="Router is down"; document.getElementById("lowersection").style.display="none"; } + setTimeout(function() {ajax(url, target, refresh);}, refresh); } } - -function requestAjax1() { ajax("/i2psnark/.ajax/xhr1.html", "mainsection"); } -function initAjax(delayMs) { setInterval(requestAjax1, delayMs); }
"); out.write(_("IPs Permanently Banned")); - out.write("
"); + out.write("
"); out.write(_("From")); - out.write(""); + out.write(""); out.write(_("To")); out.write("
"); out.write(toStr(from)); out.write(""); + out.write("
"); out.write(toStr(from)); out.write(""); int to = getTo(_blocklist[i]); if (to != from) { out.write(toStr(to)); out.write("
"); out.write(toStr(from)); out.write(""); + out.write("
"); out.write(toStr(from)); out.write(""); int to = getTo(_blocklist[i]); if (to != from) { out.write(toStr(to)); out.write("