diff --git a/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java b/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java index 30536f4ae43c32d85313350706e706c89fc06829..22bf33b5c6e45a6d2b451baa36d89fd1954d12b4 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java @@ -38,7 +38,7 @@ import net.i2p.util.EepGet; * @author Ragnarok * */ -public class AddressBook { +class AddressBook { private String location; @@ -88,6 +88,8 @@ public class AddressBook { * read or cannot be read, return an empty AddressBook. * Set a maximum size of the remote book to make it a little harder for a malicious book-sender. * + * Yes, the EepGet fetch() is done in this constructor. + * * @param subscription * A Subscription instance pointing at a remote address book. * @param proxyHost hostname of proxy @@ -102,6 +104,7 @@ public class AddressBook { if (get.fetch()) { subscription.setEtag(get.getETag()); subscription.setLastModified(get.getLastModified()); + subscription.setLastFetched(I2PAppContext.getGlobalContext().clock().now()); } try { this.addresses = ConfigParser.parse(tmp); diff --git a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java index c963ecce5456118324ae33cc5a249051da5397fd..ac471df80c321164d930f6f934af56e6defedb6c 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java @@ -35,6 +35,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import net.i2p.util.SecureFile; import net.i2p.util.SecureFileOutputStream; /** @@ -46,7 +47,7 @@ import net.i2p.util.SecureFileOutputStream; * * @author Ragnarok */ -public class ConfigParser { +class ConfigParser { /** * Strip the comments from a String. Lines that begin with '#' and ';' are @@ -142,7 +143,7 @@ public class ConfigParser { * @param file * A File to attempt to parse. * @param map - * A Map to use as the default, if file fails. + * A Map containing values to use as defaults. * @return A Map containing the key, value pairs from file, or if file * cannot be read, map. */ @@ -150,6 +151,11 @@ public class ConfigParser { Map result; try { result = ConfigParser.parse(file); + for (Iterator iter = map.keySet().iterator(); iter.hasNext(); ) { + String key = (String) iter.next(); + if (!result.containsKey(key)) + result.put(key, map.get(key)); + } } catch (IOException exp) { result = map; try { @@ -280,7 +286,7 @@ public class ConfigParser { * if file cannot be written to. */ public static void write(Map map, File file) throws IOException { - File tmp = File.createTempFile("hoststxt-", ".tmp", file.getAbsoluteFile().getParentFile()); + File tmp = SecureFile.createTempFile("hoststxt-", ".tmp", file.getAbsoluteFile().getParentFile()); ConfigParser .write(map, new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(tmp), "UTF-8"))); boolean success = tmp.renameTo(file); diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java index 2588010118eb7156ba390464c942a1d3c4325174..274fa8c4f6401e78fd991a26e481c88a17e3e782 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java @@ -38,7 +38,7 @@ import net.i2p.util.SecureDirectory; * */ public class Daemon { - public static final String VERSION = "2.0.3"; + public static final String VERSION = "2.0.4"; private static final Daemon _instance = new Daemon(); private boolean _running; @@ -66,6 +66,7 @@ public class Daemon { router.merge(master, true, null); Iterator iter = subscriptions.iterator(); while (iter.hasNext()) { + // yes, the EepGet fetch() is done in next() router.merge((AddressBook) iter.next(), false, log); } router.write(); @@ -97,6 +98,15 @@ public class Daemon { File etagsFile = new File(home, (String) settings.get("etags")); File lastModifiedFile = new File(home, (String) settings .get("last_modified")); + File lastFetchedFile = new File(home, (String) settings + .get("last_fetched")); + long delay; + try { + delay = Long.parseLong((String) settings.get("update_delay")); + } catch (NumberFormatException nfe) { + delay = 12; + } + delay *= 60 * 60 * 1000; AddressBook master = new AddressBook(masterFile); AddressBook router = new AddressBook(routerFile); @@ -106,7 +116,7 @@ public class Daemon { defaultSubs.add("http://www.i2p2.i2p/hosts.txt"); SubscriptionList subscriptions = new SubscriptionList(subscriptionFile, - etagsFile, lastModifiedFile, defaultSubs, (String) settings + etagsFile, lastModifiedFile, lastFetchedFile, delay, defaultSubs, (String) settings .get("proxy_host"), Integer.parseInt((String) settings.get("proxy_port"))); Log log = new Log(logFile); @@ -150,6 +160,7 @@ public class Daemon { defaultSettings.put("subscriptions", "subscriptions.txt"); defaultSettings.put("etags", "etags"); defaultSettings.put("last_modified", "last_modified"); + defaultSettings.put("last_fetched", "last_fetched"); defaultSettings.put("update_delay", "12"); if (!homeFile.exists()) { @@ -165,7 +176,7 @@ public class Daemon { Map settings = ConfigParser.parse(settingsFile, defaultSettings); // wait try { - Thread.sleep(5*60*1000); + Thread.sleep(5*60*1000 + I2PAppContext.getGlobalContext().random().nextLong(5*60*1000)); // Static method, and redundent Thread.currentThread().sleep(5*60*1000); } catch (InterruptedException ie) {} diff --git a/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java b/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java index 7c9e65994fc513571253e6d947b35aa7c264c434..b2ff2c5112a2ddeef4606c152af77f78af482299 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java @@ -27,7 +27,7 @@ package net.i2p.addressbook; * @author Ragnarok * */ -public class DaemonThread extends Thread { +class DaemonThread extends Thread { private String[] args; diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Log.java b/apps/addressbook/java/src/net/i2p/addressbook/Log.java index a1ba1a2fcb9996bf5ef2a12e92b7e175a8424c01..d0f01904f9ae3dc8ff113ff4393c13e2fd117116 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Log.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Log.java @@ -33,7 +33,7 @@ import java.util.Date; * @author Ragnarok * */ -public class Log { +class Log { private File file; diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java b/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java index a97635b1285c15ca5f22223badccbf2946ad9191..e391d11e231ec83a30ae3d6f9b5f6794f6e6b748 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java @@ -27,13 +27,14 @@ package net.i2p.addressbook; * @author Ragnarok * */ -public class Subscription { +class Subscription { private String location; private String etag; private String lastModified; + private long lastFetched; /** * Construct a Subscription pointing to the address book at location, that @@ -47,11 +48,17 @@ public class Subscription { * @param lastModified * the last-modified header we recieved the last time we read * this subscription. + * @param lastFetched when the subscription was last fetched (Java time, as a String) */ - public Subscription(String location, String etag, String lastModified) { + public Subscription(String location, String etag, String lastModified, String lastFetched) { this.location = location; this.etag = etag; this.lastModified = lastModified; + if (lastFetched != null) { + try { + this.lastFetched = Long.parseLong(lastFetched); + } catch (NumberFormatException nfe) {} + } } /** @@ -102,4 +109,14 @@ public class Subscription { public void setLastModified(String lastModified) { this.lastModified = lastModified; } -} \ No newline at end of file + + /** @since 0.8.2 */ + public long getLastFetched() { + return this.lastFetched; + } + + /** @since 0.8.2 */ + public void setLastFetched(long t) { + this.lastFetched = t; + } +} diff --git a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java index b033181e0011d04f7ead63677ef180c2c63c9b83..6a362b8475a67efbc33e444b7476c2928b65d65e 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java @@ -21,31 +21,39 @@ package net.i2p.addressbook; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; // debug + /** * An iterator over the subscriptions in a SubscriptionList. Note that this iterator * returns AddressBook objects, and not Subscription objects. + * Yes, the EepGet fetch() is done in here in next(). * * @author Ragnarok */ -public class SubscriptionIterator implements Iterator { +class SubscriptionIterator implements Iterator { private Iterator subIterator; private String proxyHost; private int proxyPort; + private final long delay; /** * Construct a SubscriptionIterator using the Subscriprions in List subscriptions. * * @param subscriptions * List of Subscription objects that represent address books. + * @param delay the minimum delay since last fetched for the iterator to actually fetch * @param proxyHost proxy hostname * @param proxyPort proxt port number */ - public SubscriptionIterator(List subscriptions, String proxyHost, int proxyPort) { + public SubscriptionIterator(List subscriptions, long delay, String proxyHost, int proxyPort) { this.subIterator = subscriptions.iterator(); + this.delay = delay; this.proxyHost = proxyHost; this.proxyPort = proxyPort; } @@ -58,12 +66,24 @@ public class SubscriptionIterator implements Iterator { return this.subIterator.hasNext(); } - /* (non-Javadoc) - * @see java.util.Iterator#next() + /** + * Yes, the EepGet fetch() is done in here in next(). + * + * see java.util.Iterator#next() + * @return an AddressBook (empty if the minimum delay has not been met) */ public Object next() { Subscription sub = (Subscription) this.subIterator.next(); - return new AddressBook(sub, this.proxyHost, this.proxyPort); + if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now()) { + //System.err.println("Fetching addressbook from " + sub.getLocation()); + return new AddressBook(sub, this.proxyHost, this.proxyPort); + } else { + //System.err.println("Addressbook " + sub.getLocation() + " was last fetched " + + // DataHelper.formatDuration(I2PAppContext.getGlobalContext().clock().now() - sub.getLastFetched()) + + // " ago but the minimum delay is " + + // DataHelper.formatDuration(this.delay)); + return new AddressBook(Collections.EMPTY_MAP); + } } /* (non-Javadoc) @@ -72,4 +92,4 @@ public class SubscriptionIterator implements Iterator { public void remove() { throw new UnsupportedOperationException(); } -} \ No newline at end of file +} diff --git a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java index ac5d3236dcad7f69699a6795e075e5f9f96575e3..d67cd9af53d4eb3b8bb2d062874e89b754d09ff9 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java @@ -35,13 +35,15 @@ import java.util.Map; * @author Ragnarok * */ -public class SubscriptionList { +class SubscriptionList { private List subscriptions; private File etagsFile; private File lastModifiedFile; + private File lastFetchedFile; + private final long delay; private String proxyHost; @@ -60,20 +62,24 @@ public class SubscriptionList { * @param lastModifiedFile * A file containg the last-modified headers used for conditional * GET. The file is in the format "url=leastmodified". + * @param delay the minimum delay since last fetched for the iterator to actually fetch * @param defaultSubs default subscription file * @param proxyHost proxy hostname * @param proxyPort proxy port number */ public SubscriptionList(File locationsFile, File etagsFile, - File lastModifiedFile, List defaultSubs, String proxyHost, + File lastModifiedFile, File lastFetchedFile, long delay, List defaultSubs, String proxyHost, int proxyPort) { this.subscriptions = new LinkedList(); this.etagsFile = etagsFile; this.lastModifiedFile = lastModifiedFile; + this.lastFetchedFile = lastFetchedFile; + this.delay = delay; this.proxyHost = proxyHost; this.proxyPort = proxyPort; Map etags; Map lastModified; + Map lastFetched; String location; List locations = ConfigParser.parseSubscriptions(locationsFile, defaultSubs); @@ -87,11 +93,17 @@ public class SubscriptionList { } catch (IOException exp) { lastModified = new HashMap(); } + try { + lastFetched = ConfigParser.parse(lastFetchedFile); + } catch (IOException exp) { + lastFetched = new HashMap(); + } Iterator iter = locations.iterator(); while (iter.hasNext()) { location = (String) iter.next(); - this.subscriptions.add(new Subscription(location, (String) etags - .get(location), (String) lastModified.get(location))); + this.subscriptions.add(new Subscription(location, (String) etags.get(location), + (String) lastModified.get(location), + (String) lastFetched.get(location))); } } @@ -102,18 +114,22 @@ public class SubscriptionList { * @return A SubscriptionIterator. */ public SubscriptionIterator iterator() { - return new SubscriptionIterator(this.subscriptions, this.proxyHost, + return new SubscriptionIterator(this.subscriptions, this.delay, this.proxyHost, this.proxyPort); } /** - * Write the etag and last-modified headers for each Subscription to files. + * Write the etag and last-modified headers, + * and the last-fetched time, for each Subscription to files. + * BUG - If the subscription URL is a cgi containing an '=' the files + * won't be read back correctly; the '=' should be escaped. */ public void write() { Iterator iter = this.subscriptions.iterator(); Subscription sub; Map etags = new HashMap(); Map lastModified = new HashMap(); + Map lastFetched = new HashMap(); while (iter.hasNext()) { sub = (Subscription) iter.next(); if (sub.getEtag() != null) { @@ -122,11 +138,13 @@ public class SubscriptionList { if (sub.getLastModified() != null) { lastModified.put(sub.getLocation(), sub.getLastModified()); } + lastFetched.put(sub.getLocation(), "" + sub.getLastFetched()); } try { ConfigParser.write(etags, this.etagsFile); ConfigParser.write(lastModified, this.lastModifiedFile); + ConfigParser.write(lastFetched, this.lastFetchedFile); } catch (IOException exp) { } } -} \ No newline at end of file +} diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index 8edc92fdf37b367e3652566288c7ef2bacfdc588..001928d4797438615fd61f7e8fafe8e4a9705179 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -27,6 +27,7 @@ import net.i2p.util.EepGet; import net.i2p.util.FileUtil; import net.i2p.util.Log; import net.i2p.util.SecureDirectory; +import net.i2p.util.SecureFile; import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; import net.i2p.util.Translate; @@ -244,7 +245,7 @@ public class I2PSnarkUtil { File out = null; try { // we could use the system tmp dir but deleteOnExit() doesn't seem to work on all platforms... - out = File.createTempFile("i2psnark", null, _tmpDir); + out = SecureFile.createTempFile("i2psnark", null, _tmpDir); } catch (IOException ioe) { ioe.printStackTrace(); if (out != null) diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index 3e2a4ad6312771c115b70f98c062e20dac0633dd..87aa0d35723d4acc371b3d5ff8ee9a3fdc8d71ee 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -29,6 +29,7 @@ import java.util.List; import java.util.StringTokenizer; import net.i2p.crypto.SHA1; +import net.i2p.util.SecureFile; /** * Maintains pieces on disk. Can be used to store and retrieve pieces. @@ -462,7 +463,7 @@ public class Storage /** use a saved bitfield and timestamp from a config file */ public void check(String rootDir, long savedTime, BitField savedBitField) throws IOException { - File base = new File(rootDir, filterName(metainfo.getName())); + File base = new SecureFile(rootDir, filterName(metainfo.getName())); boolean useSavedBitField = savedTime > 0 && savedBitField != null; List files = metainfo.getFiles(); @@ -623,7 +624,7 @@ public class Storage else { // The final element (file) in the hierarchy. - f = new File(base, name); + f = new SecureFile(base, name); if (!f.createNewFile() && !f.exists()) throw new IOException("Could not create file " + f); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index e1fb7837f9ff00842d16764c37eaaca2cb0b9a34..4ebdbac26d82730cdcd948c79b39ceb5addc87f3 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -174,6 +174,8 @@ public class I2PSnarkServlet extends Default { "<head><link rel=\"shortcut icon\" href=\"/themes/snark/ubergine/favicon.ico\">\n" + "<title>"); out.write(_("I2PSnark - Anonymous BitTorrent Client")); + if ("2".equals(peerParam)) + out.write(" | Debug Mode"); out.write("</title>\n"); // we want it to go to the base URI so we don't refresh with some funky action= value @@ -780,14 +782,15 @@ public class I2PSnarkServlet extends Default { // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash String announce = snark.meta.getAnnounce(); if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") || - announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/")) { + announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") || announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/")) { Map trackers = _manager.getTrackers(); for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); String name = (String)entry.getKey(); String baseURL = (String)entry.getValue(); if (!(baseURL.startsWith(announce) || // vvv hack for non-b64 announce in list vvv - (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")))) + (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")) || + (announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/") && baseURL.startsWith("http://tracker2.postman.i2p/")))) continue; int e = baseURL.indexOf('='); if (e < 0) @@ -1552,11 +1555,11 @@ public class I2PSnarkServlet extends Default { icon = "photo"; else if (mime.startsWith("audio/") || mime.equals("application/ogg") || plc.endsWith(".flac") || plc.endsWith(".m4a") || plc.endsWith(".wma") || - plc.endsWith(".ape")) + plc.endsWith(".ape") || plc.endsWith(".oga")) icon = "music"; else if (mime.startsWith("video/") || plc.endsWith(".mkv") || plc.endsWith(".m4v") || plc.endsWith(".mp4") || plc.endsWith(".wmv") || plc.endsWith(".flv") || - plc.endsWith(".ogm")) + plc.endsWith(".ogm") || plc.endsWith(".ogv")) icon = "film"; else if (mime.equals("application/zip") || mime.equals("application/x-gtar") || mime.equals("application/compress") || mime.equals("application/gzip") || diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 17049626c0afad0bc214663cdb3d973ec9bfe910..ec38052cc02159183759b6f081dfb7256b40be24 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -85,8 +85,11 @@ public class I2PTunnel implements Logging, EventDispatcher { public boolean ownDest = false; + /** the I2CP port */ public String port = System.getProperty(I2PClient.PROP_TCP_PORT, "7654"); + /** the I2CP host */ public String host = System.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1"); + /** the listen-on host. Sadly the listen-on port does not have a field. */ public String listenHost = host; public long readTimeout = -1; @@ -689,8 +692,10 @@ public class I2PTunnel implements Logging, EventDispatcher { addtask(task); notifyEvent("clientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create a client [" + host + ":"+ port + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + port + "]"); + String msg = "Invalid I2PTunnel configuration to create an HTTP Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); notifyEvent("clientTaskId", Integer.valueOf(-1)); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down @@ -763,8 +768,10 @@ public class I2PTunnel implements Logging, EventDispatcher { addtask(task); notifyEvent("httpclientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create an httpclient [" + host + ":"+ clientPort + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + clientPort + "]"); + String msg = "Invalid I2PTunnel configuration to create an HTTP Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); notifyEvent("httpclientTaskId", Integer.valueOf(-1)); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down @@ -829,7 +836,10 @@ public class I2PTunnel implements Logging, EventDispatcher { task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, (EventDispatcher) this, this); addtask(task); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create a connect client [" + host + ":"+ _port + "]", iae); + String msg = "Invalid I2PTunnel configuration to create a CONNECT client connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down // This doesn't work for CLI though... and the tunnel doesn't close itself after error, @@ -892,8 +902,10 @@ public class I2PTunnel implements Logging, EventDispatcher { addtask(task); notifyEvent("ircclientTaskId", Integer.valueOf(task.getId())); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create an ircclient [" + host + ":"+ _port + "]", iae); - l.log("Invalid I2PTunnel configuration [" + host + ":" + _port + "]"); + String msg = "Invalid I2PTunnel configuration to create an IRC client connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); notifyEvent("ircclientTaskId", Integer.valueOf(-1)); // Since nothing listens to TaskID events, use this to propagate the error to TunnelController // Otherwise, the tunnel stays up even though the port is down @@ -939,10 +951,18 @@ public class I2PTunnel implements Logging, EventDispatcher { isShared = "true".equalsIgnoreCase(args[1].trim()); ownDest = !isShared; - I2PTunnelTask task; - task = new I2PSOCKSTunnel(_port, l, ownDest, (EventDispatcher) this, this, null); - addtask(task); - notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + try { + I2PTunnelTask task = new I2PSOCKSTunnel(_port, l, ownDest, (EventDispatcher) this, this, null); + addtask(task); + notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + } catch (IllegalArgumentException iae) { + String msg = "Invalid I2PTunnel configuration to create a SOCKS Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); + notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); + throw iae; + } } else { l.log("sockstunnel <port>"); l.log(" creates a tunnel that distributes SOCKS requests."); @@ -978,10 +998,18 @@ public class I2PTunnel implements Logging, EventDispatcher { String privateKeyFile = null; if (args.length == 3) privateKeyFile = args[2]; - I2PTunnelTask task; - task = new I2PSOCKSIRCTunnel(_port, l, ownDest, (EventDispatcher) this, this, privateKeyFile); - addtask(task); - notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + try { + I2PTunnelTask task = new I2PSOCKSIRCTunnel(_port, l, ownDest, (EventDispatcher) this, this, privateKeyFile); + addtask(task); + notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId())); + } catch (IllegalArgumentException iae) { + String msg = "Invalid I2PTunnel configuration to create a SOCKS IRC Proxy connecting to the router at " + host + ':'+ port + + " and listening on " + listenHost + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); + notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); + throw iae; + } } else { l.log("socksirctunnel <port> [<sharedClient> [<privKeyFile>]]"); l.log(" creates a tunnel for SOCKS IRC."); @@ -1019,10 +1047,19 @@ public class I2PTunnel implements Logging, EventDispatcher { if (_port <= 0) throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); - StreamrConsumer task = new StreamrConsumer(_host, _port, args[2], l, (EventDispatcher) this, this); - task.startRunning(); - addtask(task); - notifyEvent("streamrtunnelTaskId", Integer.valueOf(task.getId())); + try { + StreamrConsumer task = new StreamrConsumer(_host, _port, args[2], l, (EventDispatcher) this, this); + task.startRunning(); + addtask(task); + notifyEvent("streamrtunnelTaskId", Integer.valueOf(task.getId())); + } catch (IllegalArgumentException iae) { + String msg = "Invalid I2PTunnel configuration to create a Streamr Client connecting to the router at " + host + ':'+ port + + " and sending to " + _host + ':' + port; + _log.error(getPrefix() + msg, iae); + l.log(msg); + notifyEvent("streamrtunnnelTaskId", Integer.valueOf(-1)); + throw iae; + } } else { l.log("streamrclient <host> <port> <destination>"); l.log(" creates a tunnel that receives streaming data."); @@ -1409,7 +1446,8 @@ public class I2PTunnel implements Logging, EventDispatcher { for (Iterator it = tasks.iterator(); it.hasNext();) { I2PTunnelTask t = (I2PTunnelTask) it.next(); int id = t.getId(); - _log.debug(getPrefix() + "closetask(): parsing task " + id + " (" + t.toString() + ")"); + if (_log.shouldLog(Log.DEBUG)) + _log.debug(getPrefix() + "closetask(): parsing task " + id + " (" + t.toString() + ")"); if (id == num) { closed = closetask(t, forced, l); break; @@ -1427,9 +1465,13 @@ public class I2PTunnel implements Logging, EventDispatcher { * */ private boolean closetask(I2PTunnelTask t, boolean forced, Logging l) { - l.log("Closing task " + t.getId() + (forced ? " forced..." : "...")); + if (_log.shouldLog(Log.INFO)) + _log.info("Closing task " + t.getId() + (forced ? " forced..." : "...")); + //l.log("Closing task " + t.getId() + (forced ? " forced..." : "...")); if (t.close(forced)) { - l.log("Task " + t.getId() + " closed."); + if (_log.shouldLog(Log.INFO)) + _log.info("Task " + t.getId() + " closed."); + //l.log("Task " + t.getId() + " closed."); return true; } return false; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index 71a1561eaabd667c929b16b9eb4bcf5f2a755233..54d31d29e4809b5315beb2ab787d14d023cc47c1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -128,10 +128,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna configurePool(tunnel); if (open && listenerReady) { - l.log("Ready! Port " + getLocalPort()); + l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort); notifyEvent("openBaseClientResult", "ok"); } else { - l.log("Error listening - please see the logs!"); + l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs"); notifyEvent("openBaseClientResult", "error"); } } @@ -181,7 +181,9 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna while (sockMgr == null) { verifySocketManager(); if (sockMgr == null) { - _log.log(Log.CRIT, "Unable to create socket manager (our own? " + ownDest + ")"); + _log.error("Unable to connect to router and build tunnels for " + handlerName); + // FIXME there is a loop in buildSocketManager(), do we really need another one here? + // no matter, buildSocketManager() now throws an IllegalArgumentException try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} } } @@ -212,12 +214,12 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna if (open && listenerReady) { if (openNow) - l.log("Ready! Port " + getLocalPort()); + l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort); else - l.log("Listening on port " + getLocalPort() + ", delaying tunnel open until required"); + l.log("Client ready, listening on " + tunnel.listenHost + ':' + localPort + ", delaying tunnel open until required"); notifyEvent("openBaseClientResult", "ok"); } else { - l.log("Error listening - please see the logs!"); + l.log("Client error for " + tunnel.listenHost + ':' + localPort + ", check logs"); notifyEvent("openBaseClientResult", "error"); } } @@ -257,6 +259,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna * Sets the this.sockMgr field if it is null, or if we want a new one * * We need a socket manager before getDefaultOptions() and most other things + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager */ protected void verifySocketManager() { synchronized(sockLock) { @@ -289,15 +293,33 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna /** this is ONLY for shared clients */ private static I2PSocketManager socketManager; - /** this is ONLY for shared clients */ + + /** + * this is ONLY for shared clients + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected synchronized I2PSocketManager getSocketManager() { return getSocketManager(getTunnel(), this.privKeyFile); } - /** this is ONLY for shared clients */ + + /** + * this is ONLY for shared clients + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel) { return getSocketManager(tunnel, null); } - /** this is ONLY for shared clients */ + + /** + * this is ONLY for shared clients + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static synchronized I2PSocketManager getSocketManager(I2PTunnel tunnel, String pkf) { if (socketManager != null) { I2PSession s = socketManager.getSession(); @@ -319,15 +341,43 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna return socketManager; } + /** + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected I2PSocketManager buildSocketManager() { - return buildSocketManager(getTunnel(), this.privKeyFile); + return buildSocketManager(getTunnel(), this.privKeyFile, this.l); } + /** + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel) { return buildSocketManager(tunnel, null); } - /** @param pkf absolute path or null */ + private static final int RETRY_DELAY = 20*1000; + private static final int MAX_RETRIES = 4; + + /** + * @param pkf absolute path or null + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf) { + return buildSocketManager(tunnel, pkf, null); + } + + /** + * @param pkf absolute path or null + * @return non-null + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ + protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf, Logging log) { Properties props = new Properties(); props.putAll(tunnel.getClientOptions()); int portNum = 7654; @@ -340,6 +390,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } I2PSocketManager sockManager = null; + // Todo: Can't stop a tunnel from the UI while it's in this loop (no session yet) + int retries = 0; while (sockManager == null) { if (pkf != null) { // Persistent client dest @@ -348,8 +400,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna fis = new FileInputStream(pkf); sockManager = I2PSocketManagerFactory.createManager(fis, tunnel.host, portNum, props); } catch (IOException ioe) { + if (log != null) + log.log("Error opening key file " + ioe); _log.error("Error opening key file", ioe); - // this is going to loop but if we break we'll get a NPE + throw new IllegalArgumentException("Error opening key file " + ioe); } finally { if (fis != null) try { fis.close(); } catch (IOException ioe) {} @@ -359,8 +413,22 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } if (sockManager == null) { - _log.log(Log.CRIT, "Unable to create socket manager"); - try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} + // try to make this error sensible as it will happen... sadly we can't get to the listenPort, only the listenHost + String msg = "Unable to connect to the router at " + tunnel.host + ':' + portNum + + " and build tunnels for the client"; + if (++retries < MAX_RETRIES) { + if (log != null) + log.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + _log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + } else { + if (log != null) + log.log(msg + ", giving up"); + _log.log(Log.CRIT, msg + ", giving up"); + // not clear if callers can handle null + //return null; + throw new IllegalArgumentException(msg); + } + try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {} } } sockManager.setName("Client"); @@ -479,7 +547,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna localPort = ss.getLocalPort(); } notifyEvent("clientLocalPort", new Integer(ss.getLocalPort())); - l.log("Listening for clients on port " + localPort + " of " + getTunnel().listenHost); + // duplicates message in constructor + //l.log("Listening for clients on port " + localPort + " of " + getTunnel().listenHost); // Notify constructor that port is ready synchronized (this) { @@ -608,7 +677,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } } // else the app chaining to this one closes it! } - l.log("Closing client " + toString()); + l.log("Stopping client " + toString()); open = false; try { if (ss != null) ss.close(); @@ -616,7 +685,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna ex.printStackTrace(); return false; } - l.log("Client closed."); + //l.log("Client closed."); } synchronized (_waitingSockets) { _waitingSockets.notifyAll(); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 16f8447eca8189b309ccf07f15c7da018e5dccc4..574f723feb1b4465bf9e72f43728afdeddaca706 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -115,7 +115,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R public I2PTunnelConnectClient(int localPort, Logging l, boolean ownDest, String wwwProxy, EventDispatcher notifyThis, I2PTunnel tunnel) throws IllegalArgumentException { - super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel); + super(localPort, ownDest, l, notifyThis, "HTTPS Proxy on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openConnectClientResult", "error"); @@ -128,7 +128,7 @@ public class I2PTunnelConnectClient extends I2PTunnelHTTPClientBase implements R _proxyList.add(tok.nextToken().trim()); } - setName(getLocalPort() + " -> ConnectClient [Outproxy list: " + wwwProxy + "]"); + setName("HTTPS Proxy on " + tunnel.listenHost + ':' + localPort); startRunning(); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 14289cf2fcc1c6358ce47a1bd7626595d3b820d2..1301fcd2cb44bd3de4d33b57faa8cab2b699382e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -166,7 +166,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn super(localPort, l, sockMgr, tunnel, notifyThis, clientId); // proxyList = new ArrayList(); - setName(getLocalPort() + " -> HTTPClient [NO PROXIES]"); + setName("HTTP Proxy on " + getTunnel().listenHost + ':' + localPort); startRunning(); notifyEvent("openHTTPClientResult", "ok"); @@ -178,7 +178,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn public I2PTunnelHTTPClient(int localPort, Logging l, boolean ownDest, String wwwProxy, EventDispatcher notifyThis, I2PTunnel tunnel) throws IllegalArgumentException { - super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel); + super(localPort, ownDest, l, notifyThis, "HTTP Proxy on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel); //proxyList = new ArrayList(); // We won't use outside of i2p if (waitEventValue("openBaseClientResult").equals("error")) { @@ -192,7 +192,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn _proxyList.add(tok.nextToken().trim()); } - setName(getLocalPort() + " -> HTTPClient [WWW outproxy list: " + wwwProxy + "]"); + setName("HTTP Proxy on " + tunnel.listenHost + ':' + localPort); startRunning(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index d0dc227ec1da09fde27392cfd4caab52ac4ee0a0..6938a11ef58e5e72eae0ce2b483391a2b498084d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -46,7 +46,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable ownDest, l, notifyThis, - "IRCHandler " + (++__clientId), tunnel, pkf); + "IRC Client on " + tunnel.listenHost + ':' + localPort + " #" + (++__clientId), tunnel, pkf); StringTokenizer tok = new StringTokenizer(destinations, ", "); dests = new ArrayList(2); @@ -80,7 +80,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable //return; } - setName(getLocalPort() + " -> IRCClient"); + setName("IRC Client on " + tunnel.listenHost + ':' + localPort); startRunning(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java index 96265ff161dd5b175931dc02c1ee2ceb6dbbf64c..fc39e19964cbbd7c2f93b69695c824fd0e3371f0 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java @@ -61,16 +61,24 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { private int DEFAULT_LOCALPORT = 4488; protected int localPort = DEFAULT_LOCALPORT; + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ public I2PTunnelServer(InetAddress host, int port, String privData, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { - super(host + ":" + port + " <- " + privData, notifyThis, tunnel); + super("Server at " + host + ':' + port, notifyThis, tunnel); ByteArrayInputStream bais = new ByteArrayInputStream(Base64.decode(privData)); SetUsePool(tunnel); init(host, port, bais, privData, l); } + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ public I2PTunnelServer(InetAddress host, int port, File privkey, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { - super(host + ":" + port + " <- " + privkeyname, notifyThis, tunnel); + super("Server at " + host + ':' + port, notifyThis, tunnel); SetUsePool(tunnel); FileInputStream fis = null; try { @@ -85,8 +93,12 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } } + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ public I2PTunnelServer(InetAddress host, int port, InputStream privData, String privkeyname, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { - super(host + ":" + port + " <- " + privkeyname, notifyThis, tunnel); + super("Server at " + host + ':' + port, notifyThis, tunnel); SetUsePool(tunnel); init(host, port, privData, privkeyname, l); } @@ -100,6 +112,13 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { _usePool = DEFAULT_USE_POOL; } + private static final int RETRY_DELAY = 20*1000; + private static final int MAX_RETRIES = 4; + + /** + * @throws IllegalArgumentException if the I2CP configuration is b0rked so + * badly that we cant create a socketManager + */ private void init(InetAddress host, int port, InputStream privData, String privkeyname, Logging l) { this.l = l; this.remoteHost = host; @@ -111,7 +130,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { try { portNum = Integer.parseInt(getTunnel().port); } catch (NumberFormatException nfe) { - _log.log(Log.CRIT, "Invalid port specified [" + getTunnel().port + "], reverting to " + portNum); + _log.error("Invalid port specified [" + getTunnel().port + "], reverting to " + portNum); } } @@ -125,6 +144,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } // Todo: Can't stop a tunnel from the UI while it's in this loop (no session yet) + int retries = 0; while (sockMgr == null) { synchronized (slock) { sockMgr = I2PSocketManagerFactory.createManager(privDataCopy, getTunnel().host, portNum, @@ -132,15 +152,25 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } if (sockMgr == null) { - _log.log(Log.CRIT, "Unable to create socket manager"); - try { Thread.sleep(10*1000); } catch (InterruptedException ie) {} + // try to make this error sensible as it will happen... + String msg = "Unable to connect to the router at " + getTunnel().host + ':' + portNum + + " and build tunnels for the server at " + getTunnel().listenHost + ':' + port; + if (++retries < MAX_RETRIES) { + this.l.log(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + _log.error(msg + ", retrying in " + (RETRY_DELAY / 1000) + " seconds"); + } else { + this.l.log(msg + ", giving up"); + _log.log(Log.CRIT, msg + ", giving up"); + throw new IllegalArgumentException(msg); + } + try { Thread.sleep(RETRY_DELAY); } catch (InterruptedException ie) {} privDataCopy.reset(); } } sockMgr.setName("Server"); getTunnel().addSession(sockMgr.getSession()); - l.log("Ready!"); + l.log("Tunnels ready for server at " + getTunnel().listenHost + ':' + port); notifyEvent("openServerResult", "ok"); open = true; } @@ -206,7 +236,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { } return false; } - l.log("Shutting down server " + toString()); + l.log("Stopping tunnels for server at " + getTunnel().listenHost + ':' + this.remotePort); try { if (i2pss != null) i2pss.close(); getTunnel().removeSession(sockMgr.getSession()); @@ -215,7 +245,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { _log.error("Error destroying the session", ex); //System.exit(1); } - l.log("Server shut down."); + //l.log("Server shut down."); open = false; return true; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java index d6f4dcc394a0b992ed078f836fe0ff9c118ef074..edb1434fe27efa3b83a373e1645ebeeff74f22dd 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/InternalSocketRunner.java @@ -39,7 +39,7 @@ class InternalSocketRunner implements Runnable { } } catch (IOException ex) { if (this.open) { - _log.error("Error listening for internal connections on " + this.port, ex); + _log.error("Error listening for internal connections on port " + this.port, ex); } this.open = false; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 7a9b1dbd676e3f0f35bc79391f9375f974ccc46d..4299b6d4788e9aa028858c666fd4981fa80ce12b 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -128,8 +128,8 @@ public class TunnelController implements Logging { try { doStartTunnel(); } catch (Exception e) { - _log.error("Error starting up the tunnel", e); - log("Error starting up the tunnel - " + e.getMessage()); + _log.error("Error starting the tunnel " + getName(), e); + log("Error starting the tunnel " + getName() + ": " + e.getMessage()); // if we don't acquire() then the release() in stopTunnel() won't work acquire(); stopTunnel(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java index f1bc4874c2c660a192cf25f98609cd748a35c7bf..01888d8d10481895bb96e0d782c4c3686976acc9 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSIRCTunnel.java @@ -36,7 +36,7 @@ public class I2PSOCKSIRCTunnel extends I2PSOCKSTunnel { /** @param pkf private key file name or null for transient key */ public I2PSOCKSIRCTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) { super(localPort, l, ownDest, notifyThis, tunnel, pkf); - setName(getLocalPort() + " -> SOCKSIRCTunnel"); + setName("SOCKS IRC Proxy on " + tunnel.listenHost + ':' + localPort); } /** diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java index 740aa4549b7dddec30c8a50992859a544b1dbcdc..14cafbdfdc5513079a93386f849e6b81f4f4c62f 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/socks/I2PSOCKSTunnel.java @@ -36,14 +36,14 @@ public class I2PSOCKSTunnel extends I2PTunnelClientBase { /** @param pkf private key file name or null for transient key */ public I2PSOCKSTunnel(int localPort, Logging l, boolean ownDest, EventDispatcher notifyThis, I2PTunnel tunnel, String pkf) { - super(localPort, ownDest, l, notifyThis, "SOCKSHandler", tunnel, pkf); + super(localPort, ownDest, l, notifyThis, "SOCKS Proxy on " + tunnel.listenHost + ':' + localPort, tunnel, pkf); if (waitEventValue("openBaseClientResult").equals("error")) { notifyEvent("openSOCKSTunnelResult", "error"); return; } - setName(getLocalPort() + " -> SOCKSTunnel"); + setName("SOCKS Proxy on " + tunnel.listenHost + ':' + localPort); parseOptions(); startRunning(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index c21b45ee9d2ac47d81aeaf5d94f926697f9e25a5..0640c2a3107f5c6c24e8bacdc7f4442276683e15 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -90,7 +90,7 @@ public class IndexBean { //static final String PROP_NONCE = IndexBean.class.getName() + ".nonce"; //static final String PROP_NONCE_OLD = PROP_NONCE + '2'; /** 3 wasn't enough for some browsers. They are reloading the page for some reason - maybe HEAD? @since 0.8.1 */ - private static final int MAX_NONCES = 5; + private static final int MAX_NONCES = 8; /** store nonces in a static FIFO instead of in System Properties @since 0.8.1 */ private static final List<String> _nonces = new ArrayList(MAX_NONCES + 1); @@ -226,7 +226,7 @@ public class IndexBean { // give the messages a chance to make it to the window try { Thread.sleep(1000); } catch (InterruptedException ie) {} // and give them something to look at in any case - return _("Starting tunnel..."); + return _("Starting tunnel") + ' ' + getTunnelName(_tunnel) + " &hellip"; } private String stop() { @@ -239,7 +239,7 @@ public class IndexBean { // give the messages a chance to make it to the window try { Thread.sleep(1000); } catch (InterruptedException ie) {} // and give them something to look at in any case - return _("Stopping tunnel..."); + return _("Stopping tunnel") + ' ' + getTunnelName(_tunnel) + " &hellip"; } private String saveChanges() { diff --git a/apps/i2ptunnel/jsp/editClient.jsp b/apps/i2ptunnel/jsp/editClient.jsp index be48bb2b920ec72c912b40a8bd9e21672da7820e..2b69440ac1f290e065e42f6e8d40b13e29542540 100644 --- a/apps/i2ptunnel/jsp/editClient.jsp +++ b/apps/i2ptunnel/jsp/editClient.jsp @@ -29,7 +29,7 @@ <div id="pageHeader"> </div> - <form method="post" action="index.jsp"> + <form method="post" action="list"> <div id="tunnelEditPanel" class="panel"> <div class="header"> diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp index 97a0a93c9c7eead98b070b8ccbfb2d57a6a57ac4..773d323a2bf9c88f5d683798b2e485e012f84e3b 100644 --- a/apps/i2ptunnel/jsp/editServer.jsp +++ b/apps/i2ptunnel/jsp/editServer.jsp @@ -29,7 +29,7 @@ <div id="pageHeader"> </div> - <form method="post" action="index.jsp"> + <form method="post" action="list"> <div id="tunnelEditPanel" class="panel"> <div class="header"> diff --git a/apps/i2ptunnel/jsp/index.html b/apps/i2ptunnel/jsp/index.html deleted file mode 100644 index ea1321105ebd70b339995c446e78b3377cff2f6b..0000000000000000000000000000000000000000 --- a/apps/i2ptunnel/jsp/index.html +++ /dev/null @@ -1,2 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>I2P Router Console</title></head> -<body><meta http-equiv="refresh" content="0;url=index.jsp" /><a href="index.jsp">Enter</a></body></html> diff --git a/apps/i2ptunnel/jsp/index.jsp b/apps/i2ptunnel/jsp/index.jsp index 8b7f8051eacbda8a738bdf28af0a93bb75e0a038..cf0d0067c39cf4551a8fe37a1dae821fa2cca46d 100644 --- a/apps/i2ptunnel/jsp/index.jsp +++ b/apps/i2ptunnel/jsp/index.jsp @@ -44,7 +44,7 @@ <div class="footer"> <div class="toolbox"> - <a class="control" href="index.jsp"><%=intl._("Refresh")%></a> + <a class="control" href="list"><%=intl._("Refresh")%></a> </div> </div> </div> @@ -53,7 +53,7 @@ <div class="header"></div> <div class="footer"> <div class="toolbox"> - <a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Stop%20all"><%=intl._("Stop All")%></a> <a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Start%20all"><%=intl._("Start All")%></a> <a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Restart%20all"><%=intl._("Restart All")%></a> <a class="control" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=Reload%20configuration"><%=intl._("Reload Config")%></a> + <a class="control" href="list?nonce=<%=indexBean.getNextNonce()%>&action=Stop%20all"><%=intl._("Stop All")%></a> <a class="control" href="list?nonce=<%=indexBean.getNextNonce()%>&action=Start%20all"><%=intl._("Start All")%></a> <a class="control" href="list?nonce=<%=indexBean.getNextNonce()%>&action=Restart%20all"><%=intl._("Restart All")%></a> <a class="control" href="list?nonce=<%=indexBean.getNextNonce()%>&action=Reload%20configuration"><%=intl._("Reload Config")%></a> </div> </div> </div> @@ -89,7 +89,7 @@ %> <div class="nameField rowItem"> <label><%=intl._("Name")%>:</label> - <span class="text"><a href="edit.jsp?tunnel=<%=curServer%>" title="Edit Server Tunnel Settings for <%=indexBean.getTunnelName(curServer)%>"><%=indexBean.getTunnelName(curServer)%></a></span> + <span class="text"><a href="edit?tunnel=<%=curServer%>" title="Edit Server Tunnel Settings for <%=indexBean.getTunnelName(curServer)%>"><%=indexBean.getTunnelName(curServer)%></a></span> </div> <div class="previewField rowItem"> <label><%=intl._("Points at")%>:</label> @@ -125,17 +125,17 @@ switch (indexBean.getTunnelStatus(curServer)) { case IndexBean.STARTING: %><div class="statusStarting text"><%=intl._("Starting...")%></div> - <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>"><%=intl._("Stop")%></a> + <a class="control" title="Stop this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>"><%=intl._("Stop")%></a> <% break; case IndexBean.RUNNING: %><div class="statusRunning text"><%=intl._("Running")%></div> - <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>"><%=intl._("Stop")%></a> + <a class="control" title="Stop this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curServer%>"><%=intl._("Stop")%></a> <% break; case IndexBean.NOT_RUNNING: %><div class="statusNotRunning text"><%=intl._("Stopped")%></div> - <a class="control" title="Start this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curServer%>"><%=intl._("Start")%></a> + <a class="control" title="Start this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curServer%>"><%=intl._("Start")%></a> <% break; } @@ -157,7 +157,7 @@ </div> <div class="footer"> - <form id="addNewServerTunnelForm" action="edit.jsp"> + <form id="addNewServerTunnelForm" action="edit"> <div class="toolbox"> <label><%=intl._("New server tunnel")%>:</label> @@ -209,7 +209,7 @@ %> <div class="nameField rowItem"> <label><%=intl._("Name")%>:</label> - <span class="text"><a href="edit.jsp?tunnel=<%=curClient%>" title="Edit Tunnel Settings for <%=indexBean.getTunnelName(curClient)%>"><%=indexBean.getTunnelName(curClient)%></a></span> + <span class="text"><a href="edit?tunnel=<%=curClient%>" title="Edit Tunnel Settings for <%=indexBean.getTunnelName(curClient)%>"><%=indexBean.getTunnelName(curClient)%></a></span> </div> <div class="portField rowItem"> <label><%=intl._("Port")%>:</label> @@ -229,22 +229,22 @@ switch (indexBean.getTunnelStatus(curClient)) { case IndexBean.STARTING: %><div class="statusStarting text"><%=intl._("Starting...")%></div> - <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>"><%=intl._("Stop")%></a> + <a class="control" title="Stop this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>"><%=intl._("Stop")%></a> <% break; case IndexBean.STANDBY: %><div class="statusStarting text"><%=intl._("Standby")%></div> - <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>"><%=intl._("Stop")%></a> + <a class="control" title="Stop this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>"><%=intl._("Stop")%></a> <% break; case IndexBean.RUNNING: %><div class="statusRunning text"><%=intl._("Running")%></div> - <a class="control" title="Stop this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>"><%=intl._("Stop")%></a> + <a class="control" title="Stop this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=stop&tunnel=<%=curClient%>"><%=intl._("Stop")%></a> <% break; case IndexBean.NOT_RUNNING: %><div class="statusNotRunning text"><%=intl._("Stopped")%></div> - <a class="control" title="Start this Tunnel" href="index.jsp?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curClient%>"><%=intl._("Start")%></a> + <a class="control" title="Start this Tunnel" href="list?nonce=<%=indexBean.getNextNonce()%>&action=start&tunnel=<%=curClient%>"><%=intl._("Start")%></a> <% break; } @@ -285,7 +285,7 @@ </div> <div class="footer"> - <form id="addNewClientTunnelForm" action="edit.jsp"> + <form id="addNewClientTunnelForm" action="edit"> <div class="toolbox"> <label><%=intl._("New client tunnel")%>:</label> diff --git a/apps/i2ptunnel/jsp/web.xml b/apps/i2ptunnel/jsp/web.xml index a814e9a87b02057116d5f3f1347747e052e4d044..d333d29367bbf91160e86d6bc685e6232e07221a 100644 --- a/apps/i2ptunnel/jsp/web.xml +++ b/apps/i2ptunnel/jsp/web.xml @@ -5,6 +5,19 @@ <web-app> <!-- precompiled servlets --> + + <!-- yeah we could do this in a handler but this is easier --> + <servlet-mapping> + <servlet-name>net.i2p.i2ptunnel.jsp.index_jsp</servlet-name> + <!-- this becomes the default so it also covers /index and /index.html --> + <url-pattern>/</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>net.i2p.i2ptunnel.jsp.edit_jsp</servlet-name> + <url-pattern>/edit</url-pattern> + </servlet-mapping> + <session-config> <session-timeout> 30 diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java index 40371a8333e940b063ac42abf14857c7e67fe48f..c97647fc97b16af1cb07513c91b8489dccf332e6 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNavHelper.java @@ -22,8 +22,8 @@ public class ConfigNavHelper extends HelperBase { public void renderNavBar(String requestURI) throws IOException { StringBuilder buf = new StringBuilder(1024); for (int i = 0; i < pages.length; i++) { - String page = "config" + pages[i] + ".jsp"; - if (requestURI.indexOf(page) != -1) { + String page = "config" + pages[i]; + if (requestURI.endsWith(page) || requestURI.endsWith(page + ".jsp")) { // we are there buf.append(_(titles[i])); } else { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java index 693febddcb0b5ddfc25b763e99b6ad91db0c7677..a0a3df8c9d4b15f40020cf86b7d612b3651656ce 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java @@ -20,7 +20,7 @@ public class ConfigPeerHandler extends FormHandler { } else if (_action.equals(_("Ban peer until restart"))) { Hash h = getHash(); if (h != null) { - _context.shitlist().shitlistRouterForever(h, _("Manually banned via {0}"), "<a href=\"configpeer.jsp\">configpeer.jsp</a>"); + _context.shitlist().shitlistRouterForever(h, _("Manually banned via {0}"), "<a href=\"configpeer\">configpeer</a>"); addFormNotice(_("Peer") + " " + _peer + " " + _("banned until restart") ); return; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java index ccd96e7a0eb4def70a6dee669d897ea152fc0d12..d36cfbaf906989c34c4f9904ddae5602658389ef 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java @@ -81,7 +81,7 @@ public class ConfigRestartBean { /** @param s value,label,... pairs */ private static void buttons(RouterContext ctx, StringBuilder buf, String url, String nonce, String[] s) { - buf.append("<form action=\"").append(url).append("\" method=\"GET\">\n"); + buf.append("<form action=\"").append(url).append("\" method=\"POST\">\n"); buf.append("<input type=\"hidden\" name=\"consoleNonce\" value=\"").append(nonce).append("\" >\n"); for (int i = 0; i < s.length; i+= 2) buf.append("<button type=\"submit\" name=\"action\" value=\"").append(s[i]).append("\" >").append(_(s[i+1], ctx)).append("</button>\n"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java index 8f359e25cd5758214ccff62dea48bd899276a74b..8c0925e4bc38305ddd534b8f9fffb68ad5608661 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java @@ -29,7 +29,7 @@ public class ConfigUIHandler extends FormHandler { if (_context.router().saveConfig()) { if (!oldTheme.equals(_config)) addFormNotice(_("Theme change saved.") + - " <a href=\"configui.jsp\">" + + " <a href=\"configui\">" + _("Refresh the page to view.") + "</a>"); } else { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java index 8fc78e7900a6e5e1afaa6d9384ecda9488062380..31b67dc81332ba73f054a2846e1ed00921c9c277 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -127,8 +127,8 @@ public class GraphHelper extends HelperBase { public String getForm() { saveSettings(); try { - _out.write("<br><h3>" + _("Configure Graph Display") + " [<a href=\"configstats.jsp\">" + _("Select Stats") + "</a>]</h3>"); - _out.write("<form action=\"graphs.jsp\" method=\"GET\">"); + _out.write("<br><h3>" + _("Configure Graph Display") + " [<a href=\"configstats\">" + _("Select Stats") + "</a>]</h3>"); + _out.write("<form action=\"graphs\" method=\"POST\">"); _out.write(_("Periods") + ": <input size=\"3\" type=\"text\" name=\"periodCount\" value=\"" + _periodCount + "\"><br>\n"); _out.write(_("Plot averages") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"false\" " + (_showEvents ? "" : "checked=\"true\" ") + "> "); _out.write(_("or")+ " " +_("plot events") + ": <input type=\"radio\" class=\"optbox\" name=\"showEvents\" value=\"true\" "+ (_showEvents ? "checked=\"true\" " : "") + "><br>\n"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java index a075fb62f2fc993e69209493ad34fc4a693d7818..91ede9e5297d0e89808e89b79b5d30c55380be52 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LocaleWebAppHandler.java @@ -13,7 +13,9 @@ import org.mortbay.jetty.servlet.WebApplicationHandler; /** * Convert foo.jsp to foo_xx.jsp for language xx. * This is appropriate for jsps with large amounts of text. - * This does not work for included jsps (e.g. summary*) + * + * Also, as of 0.8.2, rewrite "/" and "/index.html" to "/index.jsp",x + * and "/foo" to "/foo.jsp". * * @author zzz */ @@ -46,9 +48,22 @@ public class LocaleWebAppHandler extends WebApplicationHandler return; } + // transparent rewriting + if (pathInContext.equals("/") || pathInContext.equals("/index.html")) { + // home page + pathInContext = "/index.jsp"; + } else if (pathInContext.indexOf("/", 1) < 0 && + !pathInContext.endsWith(".jsp")) { + // add .jsp to pages at top level + pathInContext += ".jsp"; + } + //System.err.println("Path: " + pathInContext); String newPath = pathInContext; - if (pathInContext.endsWith(".jsp")) { + //if (pathInContext.endsWith(".jsp")) { + // We only ended up doing this for help.jsp, so save some effort + // unless we translate more pages like this + if (pathInContext.equals("/help.jsp")) { int len = pathInContext.length(); // ...but leave foo_xx.jsp alone if (len < 8 || pathInContext.charAt(len - 7) != '_') { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java index d2b0a17e903c17308b8d077904826c3f1f66814f..131cacb92690d3aa936d276fa6db68f944345fcd 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -105,7 +105,7 @@ public class NetDbRenderer { public void renderLeaseSetHTML(Writer out, boolean debug) throws IOException { StringBuilder buf = new StringBuilder(4*1024); buf.append("<h2>" + _("Network Database Contents") + "</h2>\n"); - buf.append("<a href=\"netdb.jsp\">" + _("View RouterInfo") + "</a>"); + buf.append("<a href=\"netdb\">" + _("View RouterInfo") + "</a>"); buf.append("<h3>").append(_("LeaseSets")).append("</h3>\n"); Hash ourRKey; Set<LeaseSet> leases; @@ -130,7 +130,7 @@ public class NetDbRenderer { Hash key = dest.calculateHash(); buf.append("<b>").append(_("LeaseSet")).append(": ").append(key.toBase64()); if (_context.clientManager().isLocal(dest)) { - buf.append(" (<a href=\"tunnels.jsp#" + key.toBase64().substring(0,4) + "\">" + _("Local") + "</a> "); + buf.append(" (<a href=\"tunnels#" + key.toBase64().substring(0,4) + "\">" + _("Local") + "</a> "); if (! _context.clientManager().shouldPublishLeaseSet(key)) buf.append(_("Unpublished") + ' '); buf.append(_("Destination") + ' '); @@ -212,7 +212,7 @@ public class NetDbRenderer { * @param mode 0: our info and charts only; 1: full routerinfos and charts; 2: abbreviated routerinfos and charts */ public void renderStatusHTML(Writer out, int mode) throws IOException { - out.write("<h2>" + _("Network Database Contents") + " (<a href=\"netdb.jsp?l=1\">" + _("View LeaseSets") + "</a>)</h2>\n"); + out.write("<h2>" + _("Network Database Contents") + " (<a href=\"netdb?l=1\">" + _("View LeaseSets") + "</a>)</h2>\n"); if (!_context.netDb().isInitialized()) { out.write(_("Not initialized")); out.flush(); @@ -223,7 +223,7 @@ public class NetDbRenderer { boolean shortStats = mode == 2; boolean showStats = full || shortStats; Hash us = _context.routerHash(); - out.write("<a name=\"routers\" ></a><h3>" + _("Routers") + " (<a href=\"netdb.jsp"); + out.write("<a name=\"routers\" ></a><h3>" + _("Routers") + " (<a href=\"netdb"); if (full || !showStats) out.write("?f=2#routers\" >" + _("Show all routers")); else @@ -343,9 +343,9 @@ public class NetDbRenderer { } else { buf.append("<b>" + _("Peer info for") + ":</b> ").append(hash).append("\n"); if (full) { - buf.append("[<a href=\"netdb.jsp\" >Back</a>]</th></tr><td>\n"); + buf.append("[<a href=\"netdb\" >Back</a>]</th></tr><td>\n"); } else { - buf.append("[<a href=\"netdb.jsp?r=").append(hash.substring(0, 6)).append("\" >").append(_("Full entry")).append("</a>]</th></tr><td>\n"); + buf.append("[<a href=\"netdb?r=").append(hash.substring(0, 6)).append("\" >").append(_("Full entry")).append("</a>]</th></tr><td>\n"); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java index 71cb982c9ab467ecad11f56b63e277fd00dde056..adb2380777f90a62d60d9bae06020c52a0de291f 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFetcher.java @@ -49,25 +49,36 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { private static final String TEMP_NEWS_FILE = "news.xml.temp"; /** @since 0.7.14 not configurable */ private static final String BACKUP_NEWS_URL = "http://www.i2p2.i2p/_static/news/news.xml"; + private static final String PROP_LAST_CHECKED = "router.newsLastChecked"; private NewsFetcher(I2PAppContext ctx) { _context = ctx; _log = ctx.logManager().getLog(NewsFetcher.class); _instance = this; - _lastFetch = 0; + try { + String last = ctx.getProperty(PROP_LAST_CHECKED); + if (last != null) + _lastFetch = Long.parseLong(last); + } catch (NumberFormatException nfe) {} _newsFile = new File(_context.getRouterDir(), NEWS_FILE); _tempFile = new File(_context.getTempDir(), TEMP_NEWS_FILE); updateLastFetched(); - _lastUpdated = _lastFetch; _updateVersion = ""; } private void updateLastFetched() { if (_newsFile.exists()) { + if (_lastUpdated == 0) + _lastUpdated = _newsFile.lastModified(); if (_lastFetch == 0) - _lastFetch = _newsFile.lastModified(); - } else + _lastFetch = _lastUpdated; + if (_lastModified == null) + _lastModified = to822Date(_lastFetch); + } else { + _lastUpdated = 0; _lastFetch = 0; + _lastModified = null; + } } public boolean updateAvailable() { return _updateAvailable; } @@ -136,7 +147,7 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { return true; } else { if (_log.shouldLog(Log.DEBUG)) - _log.debug("Last fetched " + DataHelper.formatDuration2(_context.clock().now() - _lastFetch) + " ago"); + _log.debug("Last fetched " + DataHelper.formatDuration(_context.clock().now() - _lastFetch) + " ago"); return false; } } catch (NumberFormatException nfe) { @@ -273,6 +284,11 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { return -1; } + /** @since 0.8.2 */ + private static String to822Date(long t) { + return (new SimpleDateFormat("d MMM yyyy HH:mm:ss z", Locale.US)).format(new Date(t)); + } + private static final String VERSION_STRING = "version=\"" + RouterVersion.VERSION + "\""; private static final String VERSION_PREFIX = "version=\""; private void checkForUpdates() { @@ -374,6 +390,10 @@ public class NewsFetcher implements Runnable, EepGet.StatusListener { _log.warn("Transfer complete, but no file? - probably 304 Not Modified"); } _lastFetch = now; + if (_context.isRouterContext()) { + ((RouterContext)_context).router().setConfigSetting(PROP_LAST_CHECKED, "" + now); + ((RouterContext)_context).router().saveConfig(); + } } public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java index 7265578730beb42756aede5e933fada97b4b2bc0..f452df2ba85f4700d268bb7fd7d97e77b0e7116b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java @@ -74,7 +74,7 @@ class ProfileOrganizerRenderer { if (older > 0) buf.append(_("Hiding {0} older profiles.", older)).append('\n'); if (standard > 0) - buf.append("<a href=\"/profiles.jsp?f=1\">").append(_("Hiding {0} standard profiles.", standard)).append("</a>\n"); + buf.append("<a href=\"/profiles?f=1\">").append(_("Hiding {0} standard profiles.", standard)).append("</a>\n"); buf.append("</p>"); buf.append("<table>"); buf.append("<tr>"); @@ -173,7 +173,7 @@ class ProfileOrganizerRenderer { buf.append(" </td>"); buf.append("<td nowrap align=\"center\"><a target=\"_blank\" href=\"dumpprofile.jsp?peer=") .append(peer.toBase64().substring(0,6)).append("\">").append(_("profile")).append("</a>"); - buf.append(" <a href=\"configpeer.jsp?peer=").append(peer.toBase64()).append("\">+-</a></td>\n"); + buf.append(" <a href=\"configpeer?peer=").append(peer.toBase64()).append("\">+-</a></td>\n"); buf.append("</tr>"); // let's not build the whole page in memory (~500 bytes per peer) out.write(buf.toString()); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java index f0b9c910bb25b5ab6964b78a6fd6b9f42bc45c2b..12c6678728b957a5accf86fc2aacbfd8e00d5b1c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java @@ -67,7 +67,7 @@ public class ShitlistRenderer { else buf.append(_(entry.cause)); } - buf.append(" (<a href=\"configpeer.jsp?peer=").append(key.toBase64()) + buf.append(" (<a href=\"configpeer?peer=").append(key.toBase64()) .append("#unsh\">").append(_("unban now")).append("</a>)"); buf.append("</li>\n"); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java index b229e8483925a10a4846031afbcaa9bcded7fa34..6b6a8b616368105796439cb8b9edd3db252b661b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java @@ -30,7 +30,7 @@ public class StatsGenerator { public void generateStatsPage(Writer out, boolean showAll) throws IOException { StringBuilder buf = new StringBuilder(16*1024); - buf.append("<div class=\"joblog\"><form action=\"/stats.jsp\">"); + buf.append("<div class=\"joblog\"><form action=\"\">"); buf.append("<select name=\"go\" onChange='location.href=this.value'>"); out.write(buf.toString()); buf.setLength(0); @@ -39,7 +39,7 @@ public class StatsGenerator { for (Iterator iter = groups.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); String group = (String)entry.getKey(); - buf.append("<option value=\"/stats.jsp#").append(group).append("\">"); + buf.append("<option value=\"#").append(group).append("\">"); buf.append(_(group)).append("</option>\n"); // let's just do the groups //Set stats = (Set)entry.getValue(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java index a978cceeed801e4274a953ffa71b312a8d137d3b..edae6da1385e6e4b3de380e952128f9c276329dd 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java @@ -28,7 +28,7 @@ public class SummaryBarRenderer { StringBuilder buf = new StringBuilder(8*1024); String theme = _context.getProperty(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME); - buf.append("<a href=\"/index.jsp\" target=\"_top\"><img src=\"") + buf.append("<a href=\"/\" target=\"_top\"><img src=\"") .append(CSSHelper.BASE_THEME_PATH) .append(theme) .append("/images/i2plogo.png\" alt=\"") @@ -37,7 +37,7 @@ public class SummaryBarRenderer { .append(_("I2P Router Console")) .append("\"></a><hr>") - .append("<h3><a href=\"/help.jsp\" target=\"_top\" title=\"") + .append("<h3><a href=\"/help\" target=\"_top\" title=\"") .append(_("I2P Router Help & FAQ")) .append("\">") .append(_("Help & FAQ")) @@ -51,7 +51,7 @@ public class SummaryBarRenderer { linkhelper.setMaxLines("100"); buf.append(linkhelper.getContent()); } else { - buf.append("<h3><a href=\"/configclients.jsp\" target=\"_top\" title=\"") + buf.append("<h3><a href=\"/configclients\" target=\"_top\" title=\"") .append(_("Configure startup of clients and webapps (services); manually start dormant services")) .append("\">") .append(_("I2P Services")) @@ -87,7 +87,7 @@ public class SummaryBarRenderer { .append("</td></tr></table>\n" + - "<hr><h3><a href=\"/config.jsp\" target=\"_top\" title=\"") + "<hr><h3><a href=\"/config\" target=\"_top\" title=\"") .append(_("Configure I2P Router")) .append("\">") .append(_("I2P Internals")) @@ -95,31 +95,31 @@ public class SummaryBarRenderer { "<table><tr><td>\n" + - "<a href=\"/tunnels.jsp\" target=\"_top\" title=\"") + "<a href=\"/tunnels\" target=\"_top\" title=\"") .append(_("View existing tunnels and tunnel build status")) .append("\">") .append(_("Tunnels")) .append("</a>\n" + - "<a href=\"/peers.jsp\" target=\"_top\" title=\"") + "<a href=\"/peers\" target=\"_top\" title=\"") .append(_("Show all current peer connections")) .append("\">") .append(_("Peers")) .append("</a>\n" + - "<a href=\"/profiles.jsp\" target=\"_top\" title=\"") + "<a href=\"/profiles\" target=\"_top\" title=\"") .append(_("Show recent peer performance profiles")) .append("\">") .append(_("Profiles")) .append("</a>\n" + - "<a href=\"/netdb.jsp\" target=\"_top\" title=\"") + "<a href=\"/netdb\" target=\"_top\" title=\"") .append(_("Show list of all known I2P routers")) .append("\">") .append(_("NetDB")) .append("</a>\n" + - "<a href=\"/logs.jsp\" target=\"_top\" title=\"") + "<a href=\"/logs\" target=\"_top\" title=\"") .append(_("Health Report")) .append("\">") .append(_("Logs")) @@ -131,19 +131,19 @@ public class SummaryBarRenderer { // .append(_("Jobs")) // .append("</a>\n" + - "<a href=\"/graphs.jsp\" target=\"_top\" title=\"") + "<a href=\"/graphs\" target=\"_top\" title=\"") .append(_("Graph router performance")) .append("\">") .append(_("Graphs")) .append("</a>\n" + - "<a href=\"/stats.jsp\" target=\"_top\" title=\"") + "<a href=\"/stats\" target=\"_top\" title=\"") .append(_("Textual router performance statistics")) .append("\">") .append(_("Stats")) .append("</a>\n" + - "<a href=\"/i2ptunnel/index.jsp\" target=\"_blank\" title=\"") + "<a href=\"/i2ptunnel/\" target=\"_blank\" title=\"") .append(_("Local Destinations")) .append("\">") .append(_("I2PTunnel")) @@ -156,7 +156,7 @@ public class SummaryBarRenderer { - buf.append("<hr><h3><a href=\"/help.jsp\" target=\"_top\" title=\"") + buf.append("<hr><h3><a href=\"/help\" target=\"_top\" title=\"") .append(_("I2P Router Help")) .append("\">") .append(_("General")) @@ -173,7 +173,7 @@ public class SummaryBarRenderer { .append(_helper.getIdent()) .append(", ") .append(_("never reveal it to anyone")) - .append("\" href=\"/netdb.jsp?r=.\" target=\"_top\">") + .append("\" href=\"/netdb?r=.\" target=\"_top\">") .append(_("show")) .append("</a></td></tr>\n" + @@ -194,7 +194,7 @@ public class SummaryBarRenderer { .append(_helper.getUptime()) .append("</td></tr></table>\n" + - "<hr><h4><a href=\"/config.jsp#help\" target=\"_top\" title=\"") + "<hr><h4><a href=\"/config#help\" target=\"_top\" title=\"") .append(_("Help with configuring your firewall and router for optimal I2P performance")) .append("\">") .append(_("Network")) @@ -220,7 +220,7 @@ public class SummaryBarRenderer { System.setProperty("net.i2p.router.web.UpdateHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.UpdateHandler.nonce", nonce+""); String uri = _helper.getRequestURI(); - buf.append("<p><form action=\"").append(uri).append("\" method=\"GET\">\n"); + buf.append("<p><form action=\"").append(uri).append("\" method=\"POST\">\n"); buf.append("<input type=\"hidden\" name=\"updateNonce\" value=\"").append(nonce).append("\" >\n"); if (_helper.updateAvailable()) { buf.append("<button type=\"submit\" name=\"updateAction\" value=\"signed\" >") @@ -250,7 +250,7 @@ public class SummaryBarRenderer { buf.append("<p>") .append(ConfigRestartBean.renderStatus(_helper.getRequestURI(), _helper.getAction(), _helper.getConsoleNonce())) - .append("</p><hr><h3><a href=\"/peers.jsp\" target=\"_top\" title=\"") + .append("</p><hr><h3><a href=\"/peers\" target=\"_top\" title=\"") .append(_("Show all current peer connections")) .append("\">") .append(_("Peers")) @@ -260,10 +260,11 @@ public class SummaryBarRenderer { "<tr><td align=\"left\"><b>") .append(_("Active")) - .append(":</b></td><td align=\"right\">") - .append(_helper.getActivePeers()) + .append(":</b></td><td align=\"right\">"); + int active = _helper.getActivePeers(); + buf.append(active) .append(" / ") - .append(_helper.getActiveProfiles()) + .append(Math.max(active, _helper.getActiveProfiles())) .append("</td></tr>\n" + "<tr><td align=\"left\"><b>") @@ -299,7 +300,7 @@ public class SummaryBarRenderer { boolean anotherLine = false; if (_helper.showFirewallWarning()) { - buf.append("<h4><a href=\"/config.jsp\" target=\"_top\" title=\"") + buf.append("<h4><a href=\"/config\" target=\"_top\" title=\"") .append(_("Help with firewall configuration")) .append("\">") .append(_("Check NAT/firewall")) @@ -320,7 +321,7 @@ public class SummaryBarRenderer { if (prev != null) System.setProperty("net.i2p.router.web.ReseedHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ReseedHandler.nonce", nonce+""); String uri = _helper.getRequestURI(); - buf.append("<p><form action=\"").append(uri).append("\" method=\"GET\">\n"); + buf.append("<p><form action=\"").append(uri).append("\" method=\"POST\">\n"); buf.append("<input type=\"hidden\" name=\"reseedNonce\" value=\"").append(nonce).append("\" >\n"); buf.append("<button type=\"submit\" value=\"Reseed\" >").append(_("Reseed")).append("</button></form></p>\n"); } @@ -338,7 +339,7 @@ public class SummaryBarRenderer { buf.append("<hr>"); - buf.append("<h3><a href=\"/config.jsp\" title=\"") + buf.append("<h3><a href=\"/config\" title=\"") .append(_("Configure router bandwidth allocation")) .append("\" target=\"_top\">") .append(_("Bandwidth in/out")) @@ -375,7 +376,7 @@ public class SummaryBarRenderer { .append(_helper.getOutboundTransferred()) .append("</td></tr></table>\n" + - "<hr><h3><a href=\"/tunnels.jsp\" target=\"_top\" title=\"") + "<hr><h3><a href=\"/tunnels\" target=\"_top\" title=\"") .append(_("View existing tunnels and tunnel build status")) .append("\">") .append(_("Tunnels")) @@ -406,7 +407,7 @@ public class SummaryBarRenderer { .append(_helper.getShareRatio()) .append("</td></tr>\n" + - "</table><hr><h3><a href=\"/jobs.jsp\" target=\"_top\" title=\"") + "</table><hr><h3><a href=\"/jobs\" target=\"_top\" title=\"") .append(_("What's in the router's job queue?")) .append("\">") .append(_("Congestion")) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 5f2cb891b7e92312dc49ce46a39663b79f7b1faa..c6b9a593a5ae61ee07634f47baf53e56c0bdf83d 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -362,7 +362,7 @@ public class SummaryHelper extends HelperBase { List<Destination> clients = new ArrayList(_context.clientManager().listClients()); StringBuilder buf = new StringBuilder(512); - buf.append("<h3><a href=\"/i2ptunnel/index.jsp\" target=\"_blank\" title=\"").append(_("Add/remove/edit & control your client and server tunnels")).append("\">").append(_("Local Destinations")).append("</a></h3><hr><div class=\"tunnels\">"); + buf.append("<h3><a href=\"/i2ptunnel/\" target=\"_blank\" title=\"").append(_("Add/remove/edit & control your client and server tunnels")).append("\">").append(_("Local Destinations")).append("</a></h3><hr><div class=\"tunnels\">"); if (!clients.isEmpty()) { Collections.sort(clients, new AlphaComparator()); buf.append("<table>"); @@ -377,7 +377,7 @@ public class SummaryHelper extends HelperBase { buf.append("server.png\" alt=\"Server\" title=\"" + _("Server") + "\">"); else buf.append("client.png\" alt=\"Client\" title=\"" + _("Client") + "\">"); - buf.append("</td><td align=\"left\"><b><a href=\"tunnels.jsp#").append(h.toBase64().substring(0,4)); + buf.append("</td><td align=\"left\"><b><a href=\"tunnels#").append(h.toBase64().substring(0,4)); buf.append("\" target=\"_top\" title=\"" + _("Show tunnels") + "\">"); if (name.length() < 16) buf.append(name); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java index 3d52c653fa313ce673995bb7d4df86df3bf2fad4..bed2647d28969c72a79ef7969e2fb7f2a058f202 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java @@ -38,7 +38,7 @@ public class TunnelRenderer { } public void renderStatusHTML(Writer out) throws IOException { - out.write("<div class=\"wideload\"><h2><a name=\"exploratory\" ></a>" + _("Exploratory tunnels") + " (<a href=\"/configtunnels.jsp#exploratory\">" + _("configure") + "</a>)</h2>\n"); + out.write("<div class=\"wideload\"><h2><a name=\"exploratory\" ></a>" + _("Exploratory tunnels") + " (<a href=\"/configtunnels#exploratory\">" + _("configure") + "</a>)</h2>\n"); renderPool(out, _context.tunnelManager().getInboundExploratoryPool(), _context.tunnelManager().getOutboundExploratoryPool()); List<Hash> destinations = null; @@ -60,7 +60,7 @@ public class TunnelRenderer { out.write("<h2><a name=\"" + client.toBase64().substring(0,4) + "\" ></a>" + _("Client tunnels for") + ' ' + _(name)); if (_context.clientManager().isLocal(client)) - out.write(" (<a href=\"/configtunnels.jsp#" + client.toBase64().substring(0,4) +"\">" + _("configure") + "</a>)</h2>\n"); + out.write(" (<a href=\"/configtunnels#" + client.toBase64().substring(0,4) +"\">" + _("configure") + "</a>)</h2>\n"); else out.write(" (" + _("dead") + ")</h2>\n"); renderPool(out, in, outPool); diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index 3374cc07a00298fb2e8481c41a5aa8b4ba6a2518..2cb8a3aed8cde690f8b6795249ddf7a33462c736 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -20,7 +20,7 @@ <jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <jsp:getProperty name="formhandler" property="allMessages" /> <div class="configure"> - <form action="config.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigNetHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigNetHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigNetHandler.nonce", new java.util.Random().nextLong()+""); %> @@ -96,7 +96,7 @@ <a href="#chelp"><%=intl._("There is help below.")%></a></b> </p><p><b><%=intl._("UPnP Configuration")%>:</b><br> <input type="checkbox" class="optbox" name="upnp" value="true" <jsp:getProperty name="nethelper" property="upnpChecked" /> > - <%=intl._("Enable UPnP to open firewall ports")%> - <a href="peers.jsp#upnp"><%=intl._("UPnP status")%></a> + <%=intl._("Enable UPnP to open firewall ports")%> - <a href="peers#upnp"><%=intl._("UPnP status")%></a> </p><p><b><%=intl._("IP Configuration")%>:</b><br> <%=intl._("Externally reachable hostname or IP address")%>:<br> <input type="radio" class="optbox" name="udpAutoIP" value="local,upnp,ssu" <%=nethelper.getUdpAutoIPChecked(3) %> > @@ -196,7 +196,7 @@ <li class="tidylist"><%=intl._("Multiple firewall/routers in the internet connection path")%> <li class="tidylist"><%=intl._("UPnP device change, reset, or address change")%> </ul></p><p> -<a href="peers.jsp#upnp"><%=intl._("Review the UPnP status here.")%></a> +<a href="peers#upnp"><%=intl._("Review the UPnP status here.")%></a> <%=intl._("UPnP may be enabled or disabled above, but a change requires a router restart to take effect.")%></p> <p><%=intl._("Hostnames entered above will be published in the network database.")%> <%=intl._("They are <b>not private</b>.")%> diff --git a/apps/routerconsole/jsp/configadvanced.jsp b/apps/routerconsole/jsp/configadvanced.jsp index 727bb084679276a21da3d6e06cfed9b96d3a743b..566d0c1bad29ffef47acd2b3c723b110fb3fadb7 100644 --- a/apps/routerconsole/jsp/configadvanced.jsp +++ b/apps/routerconsole/jsp/configadvanced.jsp @@ -23,7 +23,7 @@ <jsp:getProperty name="formhandler" property="allMessages" /> <div class="configure"> <div class="wideload"> - <form action="configadvanced.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigAdvancedHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigAdvancedHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigAdvancedHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configclients.jsp b/apps/routerconsole/jsp/configclients.jsp index c9a668c79791eaf9b91b8480e7bf670264fcd700..49430e2065b1f8697dc1b83591aa1b617cdfc7bd 100644 --- a/apps/routerconsole/jsp/configclients.jsp +++ b/apps/routerconsole/jsp/configclients.jsp @@ -26,7 +26,7 @@ button span.hide{ <jsp:setProperty name="formhandler" property="nonce" value="<%=request.getParameter("nonce")%>" /> <jsp:setProperty name="formhandler" property="settings" value="<%=request.getParameterMap()%>" /> <jsp:getProperty name="formhandler" property="allMessages" /> - <div class="configure"><form action="configclients.jsp" method="POST"> + <div class="configure"><form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigClientsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigClientsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigClientsHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configkeyring.jsp b/apps/routerconsole/jsp/configkeyring.jsp index dc265ba1b5c7d5e25e23c07752fb97cc191548d6..84cd543845ba7e2d8458740ec2dd463c6e5c52a3 100644 --- a/apps/routerconsole/jsp/configkeyring.jsp +++ b/apps/routerconsole/jsp/configkeyring.jsp @@ -25,14 +25,14 @@ <jsp:getProperty name="keyringhelper" property="summary" /> </p></div> - <form action="configkeyring.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigKeyringHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigKeyringHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigKeyringHandler.nonce", new java.util.Random().nextLong()+""); %> <input type="hidden" name="nonce" value="<%=System.getProperty("net.i2p.router.web.ConfigKeyringHandler.nonce")%>" > <h3><%=intl._("Manual Keyring Addition")%></h3><p> <%=intl._("Enter keys for encrypted remote destinations here.")%> - <%=intl._("Keys for local destinations must be entered on the")%> <a href="i2ptunnel/index.jsp"><%=intl._("I2PTunnel page")%></a>. + <%=intl._("Keys for local destinations must be entered on the")%> <a href="i2ptunnel/"><%=intl._("I2PTunnel page")%></a>. </p> <div class="wideload"> <p><table><tr> diff --git a/apps/routerconsole/jsp/configlogging.jsp b/apps/routerconsole/jsp/configlogging.jsp index ca30423dc211da59d53d88a34025bfe87b946ba6..a90c362d73112b3a8b5e28eabb86b292c8d1e163 100644 --- a/apps/routerconsole/jsp/configlogging.jsp +++ b/apps/routerconsole/jsp/configlogging.jsp @@ -19,7 +19,7 @@ <jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <jsp:getProperty name="formhandler" property="allMessages" /> <div class="configure"> - <form action="configlogging.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigLoggingHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigLoggingHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigLoggingHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configpeer.jsp b/apps/routerconsole/jsp/configpeer.jsp index bd53901089e2bb13d4db47d45e3cd53fdff5e645..0dfb550851b9a52c74fe057561a2534df622bb8a 100644 --- a/apps/routerconsole/jsp/configpeer.jsp +++ b/apps/routerconsole/jsp/configpeer.jsp @@ -27,7 +27,7 @@ peer = net.i2p.data.DataHelper.stripHTML(request.getParameter("peer")); // XSS %> <div class="configure"> - <form action="configpeer.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigPeerHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigPeerHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigPeerHandler.nonce", new java.util.Random().nextLong()+""); %> @@ -49,7 +49,7 @@ </div> <h3><%=intl._("Adjust Profile Bonuses")%></h3> - <p><%=intl._("Bonuses may be positive or negative, and affect the peer's inclusion in Fast and High Capacity tiers. Fast peers are used for client tunnels, and High Capacity peers are used for some exploratory tunnels. Current bonuses are displayed on the")%> <a href="profiles.jsp"><%=intl._("profiles page")%></a>.</p> + <p><%=intl._("Bonuses may be positive or negative, and affect the peer's inclusion in Fast and High Capacity tiers. Fast peers are used for client tunnels, and High Capacity peers are used for some exploratory tunnels. Current bonuses are displayed on the")%> <a href="profiles"><%=intl._("profiles page")%></a>.</p> <% long speed = 0; long capacity = 0; if (! "".equals(peer)) { // get existing bonus values? diff --git a/apps/routerconsole/jsp/configservice.jsp b/apps/routerconsole/jsp/configservice.jsp index c0554dfa0541bd93e29a76336b8e4285c2dd495a..d71c8ee39979541ea45ae7a85c693809f0f22655 100644 --- a/apps/routerconsole/jsp/configservice.jsp +++ b/apps/routerconsole/jsp/configservice.jsp @@ -17,7 +17,7 @@ <jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <jsp:getProperty name="formhandler" property="allMessages" /> <div class="configure"> - <form action="configservice.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigServiceHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigServiceHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigServiceHandler.nonce", new java.util.Random().nextLong()+""); %> @@ -60,7 +60,7 @@ <% } %> <h3><%=intl._("Debugging")%></h3> - <p><a href="/jobs.jsp"><%=intl._("View the job queue")%></a> + <p><a href="/jobs"><%=intl._("View the job queue")%></a> <% if (System.getProperty("wrapper.version") != null) { %> <p><%=intl._("At times, it may be helpful to debug I2P by getting a thread dump. To do so, please select the following option and review the thread dumped to <a href=\"logs.jsp#servicelogs\">wrapper.log</a>.")%></p> <hr><div class="formaction"> @@ -70,7 +70,7 @@ <h3><%=intl._("Launch browser on router startup?")%></h3> <p><%=intl._("I2P's main configuration interface is this web console, so for your convenience I2P can launch a web browser on startup pointing at")%> - <a href="http://127.0.0.1:7657/index.jsp">http://127.0.0.1:7657/index.jsp</a> .</p> + <a href="http://127.0.0.1:7657/">http://127.0.0.1:7657/</a> .</p> <hr><div class="formaction"> <input type="submit" name="action" value="<%=intl._("View console on startup")%>" > <input type="submit" name="action" value="<%=intl._("Do not view console on startup")%>" > diff --git a/apps/routerconsole/jsp/configstats.jsp b/apps/routerconsole/jsp/configstats.jsp index 20db1726cbeff6cfc4baa6ab8075bc17af0c4a63..1f3dd6354d8e98012db0df5b4c7962df319a6a95 100644 --- a/apps/routerconsole/jsp/configstats.jsp +++ b/apps/routerconsole/jsp/configstats.jsp @@ -65,7 +65,7 @@ function toggleAll(category) <jsp:useBean class="net.i2p.router.web.ConfigStatsHelper" id="statshelper" scope="request" /> <jsp:setProperty name="statshelper" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <div class="configure"> - <form id="statsForm" name="statsForm" action="configstats.jsp" method="POST"> + <form id="statsForm" name="statsForm" action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigStatsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigStatsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigStatsHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configtunnels.jsp b/apps/routerconsole/jsp/configtunnels.jsp index d505b741a97f700e9e979dbc8eefba8127bd270e..9a6a11a3781fc370cf1ac16d9d99099102bfdba1 100644 --- a/apps/routerconsole/jsp/configtunnels.jsp +++ b/apps/routerconsole/jsp/configtunnels.jsp @@ -29,7 +29,7 @@ <%=intl._("High CPU and/or high outbound bandwidth usage may result.")%> <%=intl._("Change these settings with care, and adjust them if you have problems.")%> <div class="wideload"> -<form action="configtunnels.jsp" method="POST"> +<form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigTunnelsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigTunnelsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigTunnelsHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configui.jsp b/apps/routerconsole/jsp/configui.jsp index 19cd125fa5835c03c3df187936740d6960e09e15..f2a0f5b0fc77452f054acee0e4b5b02a2b874b79 100644 --- a/apps/routerconsole/jsp/configui.jsp +++ b/apps/routerconsole/jsp/configui.jsp @@ -22,7 +22,7 @@ <jsp:setProperty name="formhandler" property="contextId" value="<%=(String)session.getAttribute("i2p.contextId")%>" /> <jsp:getProperty name="formhandler" property="allMessages" /> <div class="configure"><div class="topshimten"><h3><%=uihelper._("Router Console Theme")%></h3></div> - <form action="configui.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigUIHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigUIHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigUIHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/configupdate.jsp b/apps/routerconsole/jsp/configupdate.jsp index 22432f60ac3c65be55f72a77d353637d39c5eb84..21ae4fedff26d5dc04af2d0a56d3132bcb5551fe 100644 --- a/apps/routerconsole/jsp/configupdate.jsp +++ b/apps/routerconsole/jsp/configupdate.jsp @@ -21,7 +21,7 @@ <div class="messages"> <i><jsp:getProperty name="updatehelper" property="newsStatus" /></i></div> <div class="configure"> - <form action="configupdate.jsp" method="POST"> + <form action="" method="POST"> <% String prev = System.getProperty("net.i2p.router.web.ConfigUpdateHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigUpdateHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigUpdateHandler.nonce", new java.util.Random().nextLong()+""); %> diff --git a/apps/routerconsole/jsp/index.html b/apps/routerconsole/jsp/index.html deleted file mode 100644 index ea1321105ebd70b339995c446e78b3377cff2f6b..0000000000000000000000000000000000000000 --- a/apps/routerconsole/jsp/index.html +++ /dev/null @@ -1,2 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>I2P Router Console</title></head> -<body><meta http-equiv="refresh" content="0;url=index.jsp" /><a href="index.jsp">Enter</a></body></html> diff --git a/apps/routerconsole/jsp/summary.jsi b/apps/routerconsole/jsp/summary.jsi index 29be519891ba62fe92f25dc7a57012daf331b544..5a81e7af3dcd2cc457339a8b7593e211e1aa63f8 100644 --- a/apps/routerconsole/jsp/summary.jsi +++ b/apps/routerconsole/jsp/summary.jsi @@ -24,7 +24,7 @@ } else { // since we don't have an iframe this will reload the base page, and // the new delay will be passed to the iframe above - out.print("<div class=\"refresh\"><form action=\"" + request.getRequestURI() + "\" method=\"GET\">\n"); + out.print("<div class=\"refresh\"><form action=\"" + request.getRequestURI() + "\" method=\"POST\">\n"); out.print("<b>"); // We have intl defined when this is included, but not when compiled standalone. out.print(intl._("Refresh (s)")); diff --git a/apps/routerconsole/jsp/summaryframe.jsp b/apps/routerconsole/jsp/summaryframe.jsp index 2f6f19ec09c76fa412a8ded0f30daeb4db0f3afa..68959499f28f188598f758d6612cb9ac3a717de6 100644 --- a/apps/routerconsole/jsp/summaryframe.jsp +++ b/apps/routerconsole/jsp/summaryframe.jsp @@ -52,7 +52,7 @@ <% // d and shutdownSoon defined above if (!shutdownSoon) { - out.print("<div class=\"refresh\"><form action=\"summaryframe.jsp\" method=\"GET\">\n"); + out.print("<div class=\"refresh\"><form action=\"summaryframe.jsp\" method=\"POST\">\n"); if ("0".equals(d)) { out.print("<b>"); out.print(intl._("Refresh (s)")); diff --git a/build.xml b/build.xml index bc0b4cce719dd436239d2974b2f6b7f1559cc28f..0e749ce499ae1aff63cbb998d450c22041eb88bb 100644 --- a/build.xml +++ b/build.xml @@ -158,6 +158,7 @@ <ant dir="apps/susidns/src/" target="poupdate" /> </target> <target name="javadoc"> + <ant dir="apps/jetty" target="ensureJettylib" /> <mkdir dir="./build" /> <mkdir dir="./build/javadoc" /> <!-- get release and build version numbers --> @@ -581,8 +582,10 @@ <exec executable="echo" osfamily="unix" failifexecutionfails="true" output="pkg-temp/history.txt" append="true"> <arg value="EARLIER HISTORY IS AVAILABLE IN THE SOURCE PACKAGE" /> </exec> - <!-- may be pointless now, people with split directories will never see this --> + <!-- May be pointless now, people with split directories will never see this, + and for flat installs we don't want to overwrite news more recent than the update package. <copy file="installer/resources/news.xml" todir="pkg-temp/docs/" /> + --> </target> <target name="prepupdateSmall" depends="buildSmall, prepupdateRouter, prepthemeupdates"> <copy file="build/i2ptunnel.jar" todir="pkg-temp/lib/" /> diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java index 98e7d6af9aeb81b2d9435ce6151c80ab8e936150..b497796408cb2b6051d9386c3ed7dd230bf82c31 100644 --- a/core/java/src/net/i2p/I2PAppContext.java +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -114,6 +114,11 @@ public class I2PAppContext { * */ public static I2PAppContext getGlobalContext() { + // skip the global lock + I2PAppContext rv = _globalAppContext; + if (rv != null) + return rv; + synchronized (I2PAppContext.class) { if (_globalAppContext == null) { _globalAppContext = new I2PAppContext(false, null); @@ -122,6 +127,18 @@ public class I2PAppContext { return _globalAppContext; } + /** + * Pull the default context, WITHOUT creating a new one. + * Use this in static methods used early in router initialization, + * where creating a context messes things up. + * + * @return context or null + * @since 0.8.2 + */ + public static I2PAppContext getCurrentContext() { + return _globalAppContext; + } + /** * Lets root a brand new context * @@ -257,6 +274,7 @@ public class I2PAppContext { _appDir = _routerDir; } /****** + (new Exception("Initialized by")).printStackTrace(); System.err.println("Base directory: " + _baseDir.getAbsolutePath()); System.err.println("Config directory: " + _configDir.getAbsolutePath()); System.err.println("Router directory: " + _routerDir.getAbsolutePath()); diff --git a/core/java/src/net/i2p/I2PException.java b/core/java/src/net/i2p/I2PException.java index d263766ef3ebe873df70390d3b0f5f4c412cba4f..70b7fdbfca13e2f546cab40d01ec0f90f548e913 100644 --- a/core/java/src/net/i2p/I2PException.java +++ b/core/java/src/net/i2p/I2PException.java @@ -15,39 +15,28 @@ import java.io.PrintWriter; /** * Base class of I2P exceptions * + * This was originally used to provide chained exceptions, but + * those were added to Exception in Java 1.4, so this class provides nothing + * extra at the moment. + * * @author jrandom */ public class I2PException extends Exception { - private Throwable _source; public I2PException() { - this(null, null); + super(); } public I2PException(String msg) { - this(msg, null); - } - - public I2PException(String msg, Throwable source) { super(msg); - _source = source; } - - @Override - public void printStackTrace() { - if (_source != null) _source.printStackTrace(); - super.printStackTrace(); + + public I2PException(String msg, Throwable cause) { + super(msg, cause); } - @Override - public void printStackTrace(PrintStream ps) { - if (_source != null) _source.printStackTrace(ps); - super.printStackTrace(ps); - } - - @Override - public void printStackTrace(PrintWriter pw) { - if (_source != null) _source.printStackTrace(pw); - super.printStackTrace(pw); + /** @since 0.8.2 */ + public I2PException(Throwable cause) { + super(cause); } -} \ No newline at end of file +} diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index cd60b60cc014933e3664227226d6798a2a5fecbc..783222bc95f2132bbbc4434d02b4b8d023520b74 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -304,7 +304,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa while (!_dateReceived) { if (waitcount++ > 30) { closeSocket(); - throw new IOException("no date handshake"); + throw new IOException("No handshake received from the router"); } try { synchronized (_dateReceivedLock) { @@ -327,7 +327,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa _producer.disconnect(this); } catch (I2PSessionException ipe) {} closeSocket(); - throw new IOException("no leaseset"); + throw new IOException("No tunnels built after waiting 5 minutes... are there network problems?"); } synchronized (_leaseSetWait) { try { @@ -346,11 +346,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa } catch (UnknownHostException uhe) { _closed = true; setOpening(false); - throw new I2PSessionException(getPrefix() + "Invalid session configuration", uhe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe); } catch (IOException ioe) { _closed = true; setOpening(false); - throw new I2PSessionException(getPrefix() + "Problem connecting to " + _hostname + " on port " + _portNum, ioe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe); } } diff --git a/core/java/src/net/i2p/client/I2PSessionListener.java b/core/java/src/net/i2p/client/I2PSessionListener.java index 6e01d994f124496a60c4d75b8b13fc39e723164c..a76c6ab0f0818d7a357e9583763a42dad3c3ed39 100644 --- a/core/java/src/net/i2p/client/I2PSessionListener.java +++ b/core/java/src/net/i2p/client/I2PSessionListener.java @@ -39,7 +39,7 @@ public interface I2PSessionListener { /** * Notify the client that some error occurred - * @param null can be null? or not? + * @param error can be null? or not? */ void errorOccurred(I2PSession session, String message, Throwable error); } diff --git a/core/java/src/net/i2p/client/I2PSimpleSession.java b/core/java/src/net/i2p/client/I2PSimpleSession.java index af5ab9a75b08dc91990e32c8e5669d5fea6a738a..f4bc3e812ca6d42f8f4c58be9985ec049ffdf56b 100644 --- a/core/java/src/net/i2p/client/I2PSimpleSession.java +++ b/core/java/src/net/i2p/client/I2PSimpleSession.java @@ -86,10 +86,10 @@ class I2PSimpleSession extends I2PSessionImpl2 { } catch (UnknownHostException uhe) { _closed = true; - throw new I2PSessionException(getPrefix() + "Bad host ", uhe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, uhe); } catch (IOException ioe) { _closed = true; - throw new I2PSessionException(getPrefix() + "Problem connecting to " + _hostname + " on port " + _portNum, ioe); + throw new I2PSessionException(getPrefix() + "Cannot connect to the router on " + _hostname + ':' + _portNum, ioe); } } diff --git a/core/java/src/net/i2p/crypto/TrustedUpdate.java b/core/java/src/net/i2p/crypto/TrustedUpdate.java index 7e8a2b158588785a1dc860331cbe33be0d480e48..11f267712f88cc0ba15c3c288c83960d2a4bdd13 100644 --- a/core/java/src/net/i2p/crypto/TrustedUpdate.java +++ b/core/java/src/net/i2p/crypto/TrustedUpdate.java @@ -164,7 +164,7 @@ JXQAnA28vDmMMMH/WPbC5ixmJeGGNUiR addKey(propertyTrustedKeysTokens.nextToken().trim(), ""); } else { - addKey(DEFAULT_TRUSTED_KEY, "jrandom@mail.i2p"); + //addKey(DEFAULT_TRUSTED_KEY, "jrandom@mail.i2p"); addKey(DEFAULT_TRUSTED_KEY2, "zzz@mail.i2p"); //addKey(DEFAULT_TRUSTED_KEY3, "complication@mail.i2p"); addKey(DEFAULT_TRUSTED_KEY4, "HungryHobo@mail.i2p"); diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java index dc445a37aeb420e2b068fb2a78c259e46314bf25..eab03576da5aad78e1e2cd6ab3bc921f2d6ff924 100644 --- a/core/java/src/net/i2p/data/PrivateKeyFile.java +++ b/core/java/src/net/i2p/data/PrivateKeyFile.java @@ -80,10 +80,13 @@ public class PrivateKeyFile { if (args[0].equals("-n")) { // Cert constructor generates a null cert pkf.setCertType(Certificate.CERTIFICATE_TYPE_NULL); + System.out.println("New destination with null cert is:"); } else if (args[0].equals("-u")) { pkf.setCertType(99); + System.out.println("New destination with unknown cert is:"); } else if (args[0].equals("-x")) { pkf.setCertType(Certificate.CERTIFICATE_TYPE_HIDDEN); + System.out.println("New destination with hidden cert is:"); } else if (args[0].equals("-h")) { int hashEffort = HASH_EFFORT; if (args.length == 3) @@ -91,12 +94,13 @@ public class PrivateKeyFile { System.out.println("Estimating hashcash generation time, stand by..."); System.out.println(estimateHashCashTime(hashEffort)); pkf.setHashCashCert(hashEffort); + System.out.println("New destination with hashcash cert is:"); } else if (args.length == 3 && args[0].equals("-s")) { // Sign dest1 with dest2's Signing Private Key PrivateKeyFile pkf2 = new PrivateKeyFile(args[2]); pkf.setSignedCert(pkf2); + System.out.println("New destination with signed cert is:"); } - System.out.println("New signed destination is:"); System.out.println(pkf); pkf.write(); verifySignature(d); @@ -318,23 +322,56 @@ public class PrivateKeyFile { byte[] data = new byte[len]; System.arraycopy(d.getPublicKey().getData(), 0, data, 0, PublicKey.KEYSIZE_BYTES); System.arraycopy(d.getSigningPublicKey().getData(), 0, data, PublicKey.KEYSIZE_BYTES, SigningPublicKey.KEYSIZE_BYTES); - Signature sig = new Signature(d.getCertificate().getPayload()); + Signature sig = new Signature(); + byte[] payload = d.getCertificate().getPayload(); + Hash signerHash = null; + if (payload == null) { + System.out.println("Bad signed cert - no payload"); + return false; + } else if (payload.length == Signature.SIGNATURE_BYTES) { + sig.setData(payload); + } else if (payload.length == Certificate.CERTIFICATE_LENGTH_SIGNED_WITH_HASH) { + byte[] pl = new byte[Signature.SIGNATURE_BYTES]; + System.arraycopy(payload, 0, pl, 0, Signature.SIGNATURE_BYTES); + sig.setData(pl); + byte[] hash = new byte[Hash.HASH_LENGTH]; + System.arraycopy(payload, Signature.SIGNATURE_BYTES, hash, 0, Hash.HASH_LENGTH); + signerHash = new Hash(hash); + System.out.println("Destination is signed by " + Base32.encode(hash) + ".b32.i2p"); + } else { + System.out.println("Bad signed cert - length = " + payload.length); + return false; + } String[] filenames = new String[] {"privatehosts.txt", "userhosts.txt", "hosts.txt"}; + int tried = 0; for (int i = 0; i < filenames.length; i++) { Properties hosts = new Properties(); try { File f = new File(filenames[i]); if ( (f.exists()) && (f.canRead()) ) { DataHelper.loadProps(hosts, f, true); + int sz = hosts.size(); + if (sz > 0) { + tried += sz; + if (signerHash == null) + System.out.println("Attempting to verify using " + sz + " hosts, this may take a while"); + } for (Iterator iter = hosts.entrySet().iterator(); iter.hasNext(); ) { Map.Entry entry = (Map.Entry)iter.next(); String s = (String) entry.getValue(); Destination signer = new Destination(s); - if (checkSignature(sig, data, signer.getSigningPublicKey())) { - System.out.println("Good signature from: " + entry.getKey()); - return true; + // make it go faster if we have the signerHash hint + if (signerHash == null || signer.calculateHash().equals(signerHash)) { + if (checkSignature(sig, data, signer.getSigningPublicKey())) { + System.out.println("Good signature from: " + entry.getKey()); + return true; + } + if (signerHash != null) { + System.out.println("Bad signature from: " + entry.getKey()); + // could probably return false here but keep going anyway + } } } } @@ -342,7 +379,10 @@ public class PrivateKeyFile { } // not found, continue to the next file } - System.out.println("No valid signer found"); + if (tried > 0) + System.out.println("No valid signer found"); + else + System.out.println("No addressbooks found to valididate signer"); return false; } diff --git a/core/java/src/net/i2p/util/SecureDirectory.java b/core/java/src/net/i2p/util/SecureDirectory.java index 30d609e96fb70d50c1c206e8005ff0024623d92a..d238cc694d18cad02704950afabe0ba60117c500 100644 --- a/core/java/src/net/i2p/util/SecureDirectory.java +++ b/core/java/src/net/i2p/util/SecureDirectory.java @@ -5,15 +5,14 @@ import java.io.File; /** * Same as File but sets the file mode after mkdir() so it can * be read and written by the owner only (i.e. 700 on linux) + * As of 0.8.2, just use SecureFile instead of this. * * @since 0.8.1 * @author zzz */ public class SecureDirectory extends File { - private static final boolean canSetPerms = - (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0; - private static final boolean isNotWindows = !System.getProperty("os.name").startsWith("Win"); + protected static final boolean isNotWindows = !System.getProperty("os.name").startsWith("Win"); public SecureDirectory(String pathname) { super(pathname); @@ -54,8 +53,8 @@ public class SecureDirectory extends File { * Tries to set the permissions to 700, * ignores errors */ - private void setPerms() { - if (!canSetPerms) + protected void setPerms() { + if (!SecureFileOutputStream.canSetPerms()) return; try { setReadable(false, false); diff --git a/core/java/src/net/i2p/util/SecureFile.java b/core/java/src/net/i2p/util/SecureFile.java new file mode 100644 index 0000000000000000000000000000000000000000..a931abb556adb5d3500abd91e4cc3f9d8593814e --- /dev/null +++ b/core/java/src/net/i2p/util/SecureFile.java @@ -0,0 +1,81 @@ +package net.i2p.util; + +import java.io.File; +import java.io.IOException; + +/** + * Same as SecureDirectory but sets the file mode after createNewFile() + * and createTempFile() also. So just use this instead. + * Probably should have just made this class in the beginning and not had two. + * + * @since 0.8.2 + * @author zzz + */ +public class SecureFile extends SecureDirectory { + + public SecureFile(String pathname) { + super(pathname); + } + + public SecureFile(String parent, String child) { + super(parent, child); + } + + public SecureFile(File parent, String child) { + super(parent, child); + } + + /** + * Sets file to mode 600 if the file is created + */ + @Override + public boolean createNewFile() throws IOException { + boolean rv = super.createNewFile(); + if (rv) + setPerms(); + return rv; + } + + /** + * Sets file to mode 600 when the file is created + */ + public static File createTempFile(String prefix, String suffix) throws IOException { + File rv = File.createTempFile(prefix, suffix); + // same thing as below but static + SecureFileOutputStream.setPerms(rv); + return rv; + } + + /** + * Sets file to mode 600 when the file is created + */ + public static File createTempFile(String prefix, String suffix, File directory) throws IOException { + File rv = File.createTempFile(prefix, suffix, directory); + // same thing as below but static + SecureFileOutputStream.setPerms(rv); + return rv; + } + + /** + * Tries to set the permissions to 600, + * ignores errors + */ + @Override + protected void setPerms() { + if (!SecureFileOutputStream.canSetPerms()) + return; + try { + setReadable(false, false); + setReadable(true, true); + setWritable(false, false); + setWritable(true, true); + if (isNotWindows && isDirectory()) { + setExecutable(false, false); + setExecutable(true, true); + } + } catch (Throwable t) { + // NoSuchMethodException or NoSuchMethodError if we somehow got the + // version detection wrong or the JVM doesn't support it + } + } +} diff --git a/core/java/src/net/i2p/util/SecureFileOutputStream.java b/core/java/src/net/i2p/util/SecureFileOutputStream.java index 01c6eba718976d2806cb04f8890b0c93ee53b7bd..9494827eb6fd8a718a2c5096b55b10ed1c157219 100644 --- a/core/java/src/net/i2p/util/SecureFileOutputStream.java +++ b/core/java/src/net/i2p/util/SecureFileOutputStream.java @@ -4,6 +4,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import net.i2p.I2PAppContext; + /** * Same as FileOutputStream but sets the file mode so it can only * be read and written by the owner only (i.e. 600 on linux) @@ -13,7 +15,7 @@ import java.io.FileOutputStream; */ public class SecureFileOutputStream extends FileOutputStream { - private static final boolean canSetPerms = + private static final boolean oneDotSix = (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0; /** @@ -51,12 +53,22 @@ public class SecureFileOutputStream extends FileOutputStream { setPerms(file); } + /** @since 0.8.2 */ + static boolean canSetPerms() { + if (!oneDotSix) + return false; + I2PAppContext ctx = I2PAppContext.getCurrentContext(); + if (ctx == null) + return true; + return !ctx.getBooleanProperty("i2p.insecureFiles"); + } + /** * Tries to set the permissions to 600, * ignores errors */ public static void setPerms(File f) { - if (!canSetPerms) + if (!canSetPerms()) return; try { f.setReadable(false, false); diff --git a/installer/resources/clients.config b/installer/resources/clients.config index db6fa628ee4f7bddd08ff3d792fd2ac578d57cfb..f82aec52687e5d872b266deecefba6e48c7d335e 100644 --- a/installer/resources/clients.config +++ b/installer/resources/clients.config @@ -34,7 +34,7 @@ clientApp.3.startOnLoad=true # load a browser pointing at the web console whenever we start up clientApp.4.main=net.i2p.apps.systray.UrlLauncher clientApp.4.name=Open Router Console in web browser at startup -clientApp.4.args=http://127.0.0.1:7657/index.jsp +clientApp.4.args=http://127.0.0.1:7657/ clientApp.4.delay=3 clientApp.4.startOnLoad=true diff --git a/installer/resources/proxy/README.txt b/installer/resources/proxy/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..dc0ca866c71c2504364bb8f7cf997d90fe8f2da4 --- /dev/null +++ b/installer/resources/proxy/README.txt @@ -0,0 +1,7 @@ +Note to translators and editors: + +These are the error pages displayed in the HTTP proxy, +with the HTTP headers prepended. + +All files in this directory must be DOS formatted with \r\n line endings, +so the HTTP header lines are standards-compliant. Thank you. diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 243c76237bc4f283681405a5154125c2fd9bbb93..cf21af11d9275b5ae750756487c4598c5e32184c 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -492,7 +492,7 @@ public class TransportManager implements TransportEventListener { t.renderStatusHTML(out, urlBase, sortFlags); } - if (_transports.size() > 0) { + if (!_transports.isEmpty()) { out.write(getTransportsLegend()); } @@ -516,6 +516,11 @@ public class TransportManager implements TransportEventListener { private final String getTransportsLegend() { StringBuilder buf = new StringBuilder(1024); + buf.append("<h3 id=\"help\">").append(_("Help")).append("</h3><div class=\"configure\"><p>") + .append(_("Your transport connection limits are automatically set based on your configured bandwidth.")) + .append('\n') + .append(_("To override these limits, add the settings i2np.ntcp.maxConnections=nnn and i2np.udp.maxConnections=nnn on the advanced configuration page.")) + .append("</p></div>\n"); buf.append("<h3>").append(_("Definitions")).append("</h3><div class=\"configure\">" + "<p><b id=\"def.peer\">").append(_("Peer")).append("</b>: ").append(_("The remote peer, identified by router hash")).append("<br>\n" + "<b id=\"def.dir\">").append(_("Dir")).append("</b>: " + diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index f0e9c9e2e921c3c6a0393397ca0b26dee62a3fbc..dc0790ac48f2372043c1be323476de5b5bfacefa 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1978,15 +1978,13 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // buf.append(' ').append(_context.blocklist().toStr(ip)); buf.append("</td>"); - long idleIn = (now-peer.getLastReceiveTime())/1000; - long idleOut = (now-peer.getLastSendTime())/1000; - if (idleIn < 0) idleIn = 0; - if (idleOut < 0) idleOut = 0; + long idleIn = Math.max(now-peer.getLastReceiveTime(), 0); + long idleOut = Math.max(now-peer.getLastSendTime(), 0); buf.append("<td class=\"cells\" align=\"right\">"); - buf.append(DataHelper.formatDuration2(1000 * idleIn)); + buf.append(DataHelper.formatDuration2(idleIn)); buf.append("&thinsp/ "); - buf.append(DataHelper.formatDuration2(1000 * idleOut)); + buf.append(DataHelper.formatDuration2(idleOut)); buf.append("</td>"); int recvBps = (idleIn > 2 ? 0 : peer.getReceiveBps()); @@ -2010,7 +2008,8 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority buf.append("</td>"); buf.append("<td class=\"cells\" align=\"right\">"); - buf.append(DataHelper.formatDuration2(peer.getClockSkew())); + long skew = peer.getClockSkew(); + buf.append(formatDuration3(peer.getClockSkew())); buf.append("</td>"); offsetTotal = offsetTotal + peer.getClockSkew(); @@ -2032,15 +2031,15 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority int rto = peer.getRTO(); buf.append("<td class=\"cells\" align=\"right\">"); - buf.append(rtt); + buf.append(DataHelper.formatDuration2(rtt)); buf.append("</td>"); buf.append("<td class=\"cells\" align=\"right\">"); - buf.append(peer.getRTTDeviation()); + buf.append(DataHelper.formatDuration2(peer.getRTTDeviation())); buf.append("</td>"); buf.append("<td class=\"cells\" align=\"right\">"); - buf.append(rto); + buf.append(DataHelper.formatDuration2(rto)); buf.append("</td>"); buf.append("<td class=\"cells\" align=\"right\">"); @@ -2104,19 +2103,19 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority // buf.append("<tr><td colspan=\"16\"><hr></td></tr>\n"); buf.append("<tr class=\"tablefooter\"> <td colspan=\"3\" align=\"left\"><b>").append(_("SUMMARY")).append("</b></td>" + "<td align=\"center\" nowrap><b>"); - buf.append(formatKBps(bpsIn)).append("thinsp;/ ").append(formatKBps(bpsOut)); + buf.append(formatKBps(bpsIn)).append(" / ").append(formatKBps(bpsOut)); long x = numPeers > 0 ? uptimeMsTotal/numPeers : 0; buf.append("</b></td>" + "<td align=\"center\"><b>").append(DataHelper.formatDuration2(x)); x = numPeers > 0 ? offsetTotal/numPeers : 0; - buf.append("</b></td><td align=\"center\"><b>").append(DataHelper.formatDuration2(x)).append("</b></td>\n" + + buf.append("</b></td><td align=\"center\"><b>").append(formatDuration3(x)).append("</b></td>\n" + "<td align=\"center\"><b>"); buf.append(numPeers > 0 ? cwinTotal/(numPeers*1024) + "K" : "0K"); buf.append("</b></td><td> </td>\n" + "<td align=\"center\"><b>"); - buf.append(numPeers > 0 ? rttTotal/numPeers : 0); + buf.append(numPeers > 0 ? DataHelper.formatDuration2(rttTotal/numPeers) : '0'); buf.append("</b></td><td> </td> <td align=\"center\"><b>"); - buf.append(numPeers > 0 ? rtoTotal/numPeers : 0); + buf.append(numPeers > 0 ? DataHelper.formatDuration2(rtoTotal/numPeers) : '0'); buf.append("</b></td><td> </td> <td align=\"center\"><b>"); buf.append(sendTotal).append("</b></td> <td align=\"center\"><b>").append(recvTotal).append("</b></td>\n" + "<td align=\"center\"><b>").append(resentTotal); @@ -2139,6 +2138,17 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority buf.setLength(0); } + /** + * @return e.g. 3 sec or -3 sec + * formatDuration2() always prints negative numbers in ms + * @since 0.8.2 + */ + private static String formatDuration3(long x) { + if (x >= 0) + return DataHelper.formatDuration2(x); + return "-" + DataHelper.formatDuration2(0 - x); + } + private static final DecimalFormat _fmt = new DecimalFormat("#,##0.00"); private static final String formatKBps(int bps) { synchronized (_fmt) {