diff --git a/INSTALL-headless.txt b/INSTALL-headless.txt index 6f5457580..3ae8a14f0 100644 --- a/INSTALL-headless.txt +++ b/INSTALL-headless.txt @@ -25,21 +25,22 @@ where there are comments labeled "PORTABLE". Do this before you run I2P for the first time. To start I2P: - (*nix): sh i2prouter start + (*nix, BSD, Mac): sh i2prouter start (win*): I2P.exe - (non-x86 platforms PPC, ARM, etc): sh runplain.sh + (platforms without wrapper support): sh runplain.sh To stop I2P (gracefully): lynx http://localhost:7657/summaryframe (click "Shutdown") + or (*nix, BSD, Mac) sh i2prouter graceful To stop I2P immediately: - sh i2prouter stop + (*nix, BSD, Mac) sh i2prouter stop To uninstall I2P: rm -rf $I2PInstallDir ~/.i2p Supported JVMs: - All platforms: Java 1.6 or higher required; 1.7 or higher recommended + All platforms: Java 1.7 or higher required Windows: OpenJDK or Oracle from http://java.com/download Linux: OpenJDK or Oracle from http://java.com/download FreeBSD: OpenJDK or Oracle from http://java.com/download diff --git a/INSTALL.txt b/INSTALL.txt index 23701b041..d9960fc3a 100644 --- a/INSTALL.txt +++ b/INSTALL.txt @@ -1,8 +1,9 @@ I2P source installation instructions Prerequisites to build from source: - Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher + Java SDK (preferably Oracle/Sun or OpenJDK) 1.7.0 or higher Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java + Certain subsystems for embedded (core, router, mstreaming, streaming, i2ptunnel) require only Java 1.6 Apache Ant 1.7.0 or higher The xgettext, msgfmt, and msgmerge tools installed from the GNU gettext package http://www.gnu.org/software/gettext/ @@ -40,29 +41,30 @@ or on Windows, just double-click on i2pinstall.exe. Or move the i2pupdate.zip file into an existing installation directory and restart. To start I2P: - (*nix): sh i2prouter start + (*nix, BSD, Mac): sh i2prouter start (win*): I2P.exe or i2prouter.bat - (non-x86 platforms PPC, ARM, etc): sh runplain.sh + (platforms without wrapper support): sh runplain.sh To install I2P as a system service: - (*nix) sh i2prouter install + (*nix, BSD, Mac) sh i2prouter install (win*) install_i2p_service_winnt.bat To uninstall I2P as a system service: - (*nix) sh i2prouter remove + (*nix, BSD, Mac) sh i2prouter remove (win*) uninstall_i2p-service_winnt.bat To stop I2P (gracefully): lynx http://localhost:7657/summaryframe (click "Shutdown") + or (*nix, BSD, Mac) sh i2prouter graceful To stop I2P immediately: - sh i2prouter stop + (*nix, BSD, Mac) sh i2prouter stop To uninstall I2P: rm -rf $I2PInstallDir ~/.i2p Supported JVMs: - Windows: Latest available from http://java.com/download (1.5+ supported) - Linux: Latest available from http://java.com/download (1.5+ supported) - FreeBSD: 1.5-compatible (NIO required) + Windows: Latest available from http://java.com/download (1.7+ supported) + Linux: Latest available from http://java.com/download (1.7+ supported) + FreeBSD: 1.7-compatible (NIO required) Other operating systems and JVMs: See http://trac.i2p2.de/wiki/java diff --git a/README.txt b/README.txt index 0a99e21a4..b7a4b8e40 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,7 @@ Prerequisites to build from source: - Java SDK (preferably Oracle/Sun or OpenJDK) 1.6.0 or higher + Java SDK (preferably Oracle/Sun or OpenJDK) 1.7.0 or higher Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java + Certain subsystems for embedded (core, router, mstreaming, streaming, i2ptunnel) require only Java 1.6 Apache Ant 1.7.0 or higher The xgettext, msgfmt, and msgmerge tools installed from the GNU gettext package http://www.gnu.org/software/gettext/ diff --git a/apps/BOB/src/net/i2p/BOB/BOB.java b/apps/BOB/src/net/i2p/BOB/BOB.java index e1106c9bb..c8b06b5e9 100644 --- a/apps/BOB/src/net/i2p/BOB/BOB.java +++ b/apps/BOB/src/net/i2p/BOB/BOB.java @@ -247,11 +247,11 @@ public class BOB implements Runnable, ClientApp { save = true; } if (!props.containsKey("inbound.length")) { - props.setProperty("inbound.length", "1"); + props.setProperty("inbound.length", "3"); save = true; } if (!props.containsKey("outbound.length")) { - props.setProperty("outbound.length", "1"); + props.setProperty("outbound.length", "3"); save = true; } if (!props.containsKey("inbound.lengthVariance")) { diff --git a/apps/addressbook/java/src/net/i2p/addressbook/ConfigIterator.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigIterator.java index 30c21d19b..10119d844 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/ConfigIterator.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/ConfigIterator.java @@ -32,6 +32,8 @@ import java.util.Locale; import java.util.Map; import java.util.NoSuchElementException; +import net.i2p.data.DataHelper; + /** * A class to iterate through a hosts.txt or config file without * reading the whole thing into memory. @@ -69,7 +71,7 @@ class ConfigIterator implements Iterator>, Closeable { String inputLine = input.readLine(); while (inputLine != null) { inputLine = ConfigParser.stripComments(inputLine); - String[] splitLine = inputLine.split("="); + String[] splitLine = DataHelper.split(inputLine, "="); if (splitLine.length == 2) { next = new ConfigEntry(splitLine[0].trim().toLowerCase(Locale.US), splitLine[1].trim()); return true; diff --git a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java index e2cd8ab2a..625b6e3d0 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.List; import java.util.Locale; import java.util.Map; +import net.i2p.data.DataHelper; import net.i2p.util.SecureFile; import net.i2p.util.SecureFileOutputStream; import net.i2p.util.SystemVersion; @@ -93,7 +94,7 @@ class ConfigParser { inputLine = input.readLine(); while (inputLine != null) { inputLine = stripComments(inputLine); - String[] splitLine = inputLine.split("="); + String[] splitLine = DataHelper.split(inputLine, "="); if (splitLine.length == 2) { result.put(splitLine[0].trim().toLowerCase(Locale.US), splitLine[1].trim()); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java index 5e7d61ae9..54e9630ed 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java +++ b/apps/i2psnark/java/src/org/klomp/snark/I2PSnarkUtil.java @@ -3,8 +3,8 @@ package org.klomp.snark; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -590,10 +590,10 @@ public class I2PSnarkUtil { */ public boolean isKnownOpenTracker(String url) { try { - URL u = new URL(url); + URI u = new URI(url); String host = u.getHost(); return host != null && SnarkManager.KNOWN_OPENTRACKERS.contains(host); - } catch (MalformedURLException mue) { + } catch (URISyntaxException use) { return false; } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java index cba955f69..fbbb1859a 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java @@ -62,7 +62,7 @@ public class Peer implements Comparable // Keeps state for in/out connections. Non-null when the handshake // was successful, the connection setup and runs - PeerState state; + volatile PeerState state; /** shared across all peers on this torrent */ MagnetState magnetState; diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java index 1f47b59b6..da1b94333 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerConnectionIn.java @@ -39,7 +39,7 @@ class PeerConnectionIn implements Runnable private static final int MAX_MSG_SIZE = Math.max(PeerState.PARTSIZE + 9, MagnetState.CHUNK_SIZE + 100); // 100 for the ext msg dictionary - private Thread thread; + private volatile Thread thread; private volatile boolean quit; long lastRcvd; @@ -75,9 +75,12 @@ class PeerConnectionIn implements Runnable thread = Thread.currentThread(); try { - PeerState ps = peer.state; - while (!quit && ps != null) + while (!quit) { + final PeerState ps = peer.state; + if (ps == null) + break; + // Common variables used for some messages. int piece; int begin; @@ -91,9 +94,9 @@ class PeerConnectionIn implements Runnable if (i == 0) { - ps.keepAliveMessage(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received keepalive from " + peer); + ps.keepAliveMessage(); continue; } @@ -101,51 +104,51 @@ class PeerConnectionIn implements Runnable switch (b) { case Message.CHOKE: - ps.chokeMessage(true); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received choke from " + peer); + ps.chokeMessage(true); break; case Message.UNCHOKE: - ps.chokeMessage(false); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received unchoke from " + peer); + ps.chokeMessage(false); break; case Message.INTERESTED: - ps.interestedMessage(true); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received interested from " + peer); + ps.interestedMessage(true); break; case Message.UNINTERESTED: - ps.interestedMessage(false); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received not interested from " + peer); + ps.interestedMessage(false); break; case Message.HAVE: piece = din.readInt(); - ps.haveMessage(piece); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received havePiece(" + piece + ") from " + peer); + ps.haveMessage(piece); break; case Message.BITFIELD: byte[] bitmap = new byte[i-1]; din.readFully(bitmap); - ps.bitfieldMessage(bitmap); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received bitmap from " + peer + ": size=" + (i-1) /* + ": " + ps.bitfield */ ); + ps.bitfieldMessage(bitmap); break; case Message.REQUEST: piece = din.readInt(); begin = din.readInt(); len = din.readInt(); - ps.requestMessage(piece, begin, len); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received request(" + piece + "," + begin + ") from " + peer); + ps.requestMessage(piece, begin, len); break; case Message.PIECE: @@ -156,9 +159,9 @@ class PeerConnectionIn implements Runnable if (req != null) { req.read(din); - ps.pieceMessage(req); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received data(" + piece + "," + begin + ") from " + peer); + ps.pieceMessage(req); } else { @@ -175,16 +178,16 @@ class PeerConnectionIn implements Runnable piece = din.readInt(); begin = din.readInt(); len = din.readInt(); - ps.cancelMessage(piece, begin, len); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received cancel(" + piece + "," + begin + ") from " + peer); + ps.cancelMessage(piece, begin, len); break; case Message.PORT: int port = din.readUnsignedShort(); - ps.portMessage(port); if (_log.shouldLog(Log.DEBUG)) _log.debug("Received port message from " + peer); + ps.portMessage(port); break; case Message.EXTENSION: @@ -247,11 +250,9 @@ class PeerConnectionIn implements Runnable if (_log.shouldLog(Log.INFO)) _log.info("IOError talking with " + peer, ioe); } - catch (Throwable t) + catch (RuntimeException t) { _log.error("Error talking with " + peer, t); - if (t instanceof OutOfMemoryError) - throw (OutOfMemoryError)t; } finally { diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index f8dadb627..b0f983313 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -911,6 +911,30 @@ public class Snark return -1; } + /** + * Bytes not received and set to skipped. + * This is not the same as the total of all skipped files, + * since pieces may span multiple files. + * + * @return exact value. or 0 if no storage yet. + * @since 0.9.24 + */ + public long getSkippedLength() { + PeerCoordinator coord = coordinator; + if (coord != null) { + // fast way + long r = getRemainingLength(); + if (r <= 0) + return 0; + long n = coord.getNeededLength(); + return r - n; + } else if (storage != null) { + // slow way + return storage.getSkippedLength(); + } + return 0; + } + /** * Does not account (i.e. includes) for skipped files. * @return number of pieces still needed (magnet mode or not), or -1 if unknown diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 688cf7e95..f8996d14b 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -189,7 +189,7 @@ public class SnarkManager implements CompleteListener { for (int i = 1; i < DEFAULT_TRACKERS.length; i += 2) { if (DEFAULT_TRACKERS[i-1].equals("TheBland") && !SigType.ECDSA_SHA256_P256.isAvailable()) continue; - String urls[] = DEFAULT_TRACKERS[i].split("=", 2); + String urls[] = DataHelper.split(DEFAULT_TRACKERS[i], "=", 2); ann.add(urls[0]); } DEFAULT_TRACKER_ANNOUNCES = Collections.unmodifiableSet(ann); @@ -1078,7 +1078,7 @@ public class SnarkManager implements CompleteListener { val = dflt; if (val == null) return Collections.emptyList(); - return Arrays.asList(val.split(",")); + return Arrays.asList(DataHelper.split(val, ",")); } /** @@ -1611,7 +1611,7 @@ public class SnarkManager implements CompleteListener { return; int filecount = metainfo.getFiles().size(); int[] rv = new int[filecount]; - String[] arr = pri.split(","); + String[] arr = DataHelper.split(pri, ","); for (int i = 0; i < filecount && i < arr.length; i++) { if (arr[i].length() > 0) { try { @@ -2051,7 +2051,7 @@ public class SnarkManager implements CompleteListener { synchronized (_snarks) { ok = monitorTorrents(dir); } - } catch (Exception e) { + } catch (RuntimeException e) { _log.error("Error in the DirectoryMonitor", e); ok = false; } @@ -2060,7 +2060,7 @@ public class SnarkManager implements CompleteListener { try { addMagnets(); doMagnets = false; - } catch (Exception e) { + } catch (RuntimeException e) { _log.error("Error in the DirectoryMonitor", e); } if (!_snarks.isEmpty()) @@ -2266,7 +2266,7 @@ public class SnarkManager implements CompleteListener { // Snark.fatal() throws a RuntimeException // don't let one bad torrent kill the whole loop addTorrent(name, null, !shouldAutoStart()); - } catch (Exception e) { + } catch (RuntimeException e) { addMessage(_t("Error: Could not add the torrent {0}", name) + ": " + e); _log.error("Unable to add the torrent " + name, e); rv = false; @@ -2285,7 +2285,7 @@ public class SnarkManager implements CompleteListener { // Snark.fatal() throws a RuntimeException // don't let one bad torrent kill the whole loop stopTorrent(name, true); - } catch (Exception e) { + } catch (RuntimeException e) { // don't bother with message } } @@ -2342,12 +2342,12 @@ public class SnarkManager implements CompleteListener { if ( (trackers == null) || (trackers.trim().length() <= 0) ) { setDefaultTrackerMap(true); } else { - String[] toks = trackers.split(","); + String[] toks = DataHelper.split(trackers, ","); for (int i = 0; i < toks.length; i += 2) { String name = toks[i].trim().replace(",", ","); String url = toks[i+1].trim().replace(",", ","); if ( (name.length() > 0) && (url.length() > 0) ) { - String urls[] = url.split("=", 2); + String urls[] = DataHelper.split(url, "=", 2); String url2 = urls.length > 1 ? urls[1] : ""; _trackerMap.put(name, new Tracker(name, urls[0], url2)); } @@ -2367,7 +2367,7 @@ public class SnarkManager implements CompleteListener { String name = DEFAULT_TRACKERS[i]; if (name.equals("TheBland") && !SigType.ECDSA_SHA256_P256.isAvailable()) continue; - String urls[] = DEFAULT_TRACKERS[i+1].split("=", 2); + String urls[] = DataHelper.split(DEFAULT_TRACKERS[i+1], "=", 2); String url2 = urls.length > 1 ? urls[1] : null; _trackerMap.put(name, new Tracker(name, urls[0], url2)); } @@ -2467,7 +2467,7 @@ public class SnarkManager implements CompleteListener { public void run() { try { run2(); - } catch (Exception e) { + } catch (RuntimeException e) { _log.error("Error starting", e); } } @@ -2595,7 +2595,7 @@ public class SnarkManager implements CompleteListener { } else { addMessageNoEscape(_t("Finished recheck of torrent {0}, unchanged", link)); } - } catch (Exception e) { + } catch (IOException e) { _log.error("Error rechecking " + snark.getBaseName(), e); addMessage(_t("Error checking the torrent {0}", snark.getBaseName()) + ": " + e); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/Storage.java b/apps/i2psnark/java/src/org/klomp/snark/Storage.java index e0014c505..0fff5b885 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Storage.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Storage.java @@ -518,6 +518,31 @@ public class Storage implements Closeable return rv; } + /** + * Call setPriority() for all changed files first, + * then call this. + * The length of all the pieces that are not yet downloaded, + * and are set to skipped. + * This is not the same as the total of all skipped files, + * since pieces may span multiple files. + * + * @return 0 on error, if complete, or if only one file + * @since 0.9.24 + */ + public long getSkippedLength() { + int[] pri = getPiecePriorities(); + if (pri == null) + return 0; + long rv = 0; + final int end = pri.length - 1; + for (int i = 0; i <= end; i++) { + if (pri[i] <= -9 && !bitfield.get(i)) { + rv += (i != end) ? piece_size : metainfo.getPieceLength(i); + } + } + return rv; + } + /** * The BitField that tells which pieces this storage contains. * Do not change this since this is the current state of the storage. @@ -748,7 +773,7 @@ public class Storage implements Closeable } rv = repl; } - } catch (Exception ex) { + } catch (RuntimeException ex) { ex.printStackTrace(); } } @@ -1483,7 +1508,7 @@ public class Storage implements Closeable break; } // switch } // while - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); error = true; } diff --git a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java index ab1116722..fc48c6d87 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java +++ b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java @@ -23,8 +23,8 @@ package org.klomp.snark; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -875,18 +875,20 @@ public class TrackerClient implements Runnable { } /** - * @param ann an announce URL + * @param ann an announce URL, may be null, returns false if null * @return true for i2p hosts only * @since 0.7.12 */ public static boolean isValidAnnounce(String ann) { - URL url; + if (ann == null) + return false; + URI url; try { - url = new URL(ann); - } catch (MalformedURLException mue) { - return false; + url = new URI(ann); + } catch (URISyntaxException use) { + return false; } - return url.getProtocol().equals("http") && + return "http".equals(url.getScheme()) && url.getHost() != null && (url.getHost().endsWith(".i2p") || url.getHost().equals("i2p")); } @@ -896,13 +898,13 @@ public class TrackerClient implements Runnable { * @since 0.9.5 */ private static Hash getHostHash(String ann) { - URL url; + URI url; try { - url = new URL(ann); - } catch (MalformedURLException mue) { + url = new URI(ann); + } catch (URISyntaxException use) { return null; } - if (!url.getProtocol().equals("http")) + if (!"http".equals(url.getScheme())) return null; String host = url.getHost(); if (host.endsWith(".i2p")) @@ -912,7 +914,7 @@ public class TrackerClient implements Runnable { if (path == null || path.length() < 517 || !path.startsWith("/")) return null; - String[] parts = path.substring(1).split("[/\\?&;]", 2); + String[] parts = DataHelper.split(path.substring(1), "[/\\?&;]", 2); return ConvertToHash.getHash(parts[0]); } return null; diff --git a/apps/i2psnark/java/src/org/klomp/snark/dht/NodeInfo.java b/apps/i2psnark/java/src/org/klomp/snark/dht/NodeInfo.java index c6fce8f14..708d2d276 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/dht/NodeInfo.java +++ b/apps/i2psnark/java/src/org/klomp/snark/dht/NodeInfo.java @@ -102,7 +102,7 @@ class NodeInfo extends SimpleDataStructure { */ public NodeInfo(String s) throws DataFormatException { super(); - String[] parts = s.split(":", 4); + String[] parts = DataHelper.split(s, ":", 4); if (parts.length != 4) throw new DataFormatException("Bad format"); byte[] nid = Base64.decode(parts[0]); @@ -225,7 +225,7 @@ class NodeInfo extends SimpleDataStructure { NodeInfo ni = (NodeInfo) o; // assume dest matches, ignore it return this.hash.equals(ni.hash) && nID.equals(ni.nID) && port == ni.port; - } catch (Exception e) { + } catch (RuntimeException e) { return false; } } 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 b0335f6a8..4d7727729 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -18,7 +18,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.TimeZone; import java.util.TreeMap; import javax.servlet.ServletConfig; @@ -2714,7 +2713,7 @@ public class I2PSnarkServlet extends BasicServlet { if (snark != null) { // first table - torrent info buf.append("\n"); - buf.append(""); } @@ -2769,7 +2768,7 @@ public class I2PSnarkServlet extends BasicServlet { if (alist != null && !alist.isEmpty()) { buf.append("\n"); } long dat = meta.getCreationDate(); SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm"); - String systemTimeZone = _context.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(_context)); if (dat > 0) { String date = fmt.format(new Date(dat)); buf.append("\n"); @@ -2819,7 +2816,7 @@ public class I2PSnarkServlet extends BasicServlet { cby = com.substring(0, 128); buf.append("\n"); @@ -2829,7 +2826,7 @@ public class I2PSnarkServlet extends BasicServlet { String date = fmt.format(new Date(dates[0])); buf.append("\n"); @@ -2838,7 +2835,7 @@ public class I2PSnarkServlet extends BasicServlet { String date = fmt.format(new Date(dates[1])); buf.append("\n"); @@ -2852,7 +2849,7 @@ public class I2PSnarkServlet extends BasicServlet { buf.append("&tr=").append(announce); buf.append("\">") .append(toImg("magnet", _t("Magnet link"))) - .append("Magnet:\n"); } else { - buf.append("\n"); } @@ -2874,7 +2873,7 @@ public class I2PSnarkServlet extends BasicServlet { buf.append("
") + buf.append("
") .append(_t("Torrent")) .append(": ") .append(DataHelper.escapeHTML(snark.getBaseName())) @@ -2724,7 +2723,7 @@ public class I2PSnarkServlet extends BasicServlet { String baseName = encodePath((new File(fullPath)).getName()); buf.append("
"); toThemeImg(buf, "file"); - buf.append(" ") + buf.append("") .append(_t("Torrent file")) .append(": ") .append(DataHelper.escapeHTML(fullPath)) @@ -2732,7 +2731,7 @@ public class I2PSnarkServlet extends BasicServlet { if (snark.getStorage() != null) { buf.append("
"); toThemeImg(buf, "file"); - buf.append(" ") + buf.append("") .append(_t("Data location")) .append(": ") .append(DataHelper.escapeHTML(snark.getStorage().getBase().getPath())) @@ -2741,7 +2740,7 @@ public class I2PSnarkServlet extends BasicServlet { String hex = I2PSnarkUtil.toHex(snark.getInfoHash()); buf.append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Info hash")) .append(": ") .append(hex.toUpperCase(Locale.US)) @@ -2761,7 +2760,7 @@ public class I2PSnarkServlet extends BasicServlet { buf.append(trackerLink); else toThemeImg(buf, "details"); - buf.append(" ").append(_t("Primary Tracker")).append(": "); + buf.append("").append(_t("Primary Tracker")).append(": "); buf.append(getShortTrackerLink(announce, snark.getInfoHash())); buf.append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Tracker List")).append(": "); for (List alist2 : alist) { buf.append('['); @@ -2794,21 +2793,19 @@ public class I2PSnarkServlet extends BasicServlet { com = com.substring(0, 1024); buf.append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Comment")).append(": ") .append(DataHelper.stripHTML(com)) .append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Created")).append(": ") .append(date) .append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Created By")).append(": ") .append(DataHelper.stripHTML(cby)) .append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Added")).append(": ") .append(date) .append("
"); toThemeImg(buf, "details"); - buf.append(" ") + buf.append("") .append(_t("Completed")).append(": ") .append(date) .append("
Magnet: ") .append("
") + buf.append("
"); + toThemeImg(buf, "details"); + buf.append("") .append(_t("Private torrent")) .append("
"); toThemeImg(buf, "size"); - buf.append(" ") + buf.append("") .append(_t("Size")) .append(": ") .append(formatSize(snark.getTotalLength())); @@ -2917,6 +2916,15 @@ public class I2PSnarkServlet extends BasicServlet { .append(": ") .append(formatSize(needed)); } + long skipped = snark.getSkippedLength(); + if (skipped > 0) { + buf.append(" "); + toThemeImg(buf, "head_rx"); + buf.append(" ") + .append(_t("Skipped")) + .append(": ") + .append(formatSize(skipped)); + } if (meta != null) { List> files = meta.getFiles(); int fileCount = files != null ? files.size() : 1; @@ -2943,20 +2951,19 @@ public class I2PSnarkServlet extends BasicServlet { // buttons if (showStopStart) { - buf.append("
"); - toThemeImg(buf, "file"); + buf.append("
"); if (snark.isChecking()) { - buf.append(" ").append(_t("Checking")).append("… ") + buf.append("").append(_t("Checking")).append("… ") .append((new DecimalFormat("0.00%")).format(snark.getCheckingProgress())) .append("   ") .append(_t("Refresh page for results")).append(""); } else if (snark.isStarting()) { - buf.append(" ").append(_t("Starting")).append("…"); + buf.append("").append(_t("Starting")).append("…"); } else if (snark.isAllocating()) { - buf.append(" ").append(_t("Allocating")).append("…"); + buf.append("").append(_t("Allocating")).append("…"); } else { boolean isRunning = !snark.isStopped(); - buf.append(" \n"); else diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ConnThrottler.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ConnThrottler.java index c802a9995..de9188d8e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ConnThrottler.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ConnThrottler.java @@ -7,7 +7,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.TimeZone; import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; @@ -57,9 +56,7 @@ class ConnThrottler { _log = log; // for logging _fmt = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM); - String systemTimeZone = I2PAppContext.getGlobalContext().getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - _fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + _fmt.setTimeZone(DataHelper.getSystemTimeZone(I2PAppContext.getGlobalContext())); new Cleaner(); } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/GunzipOutputStream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/GunzipOutputStream.java index e0798567d..6f5a4c3a7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/GunzipOutputStream.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/GunzipOutputStream.java @@ -105,7 +105,7 @@ class GunzipOutputStream extends InflaterOutputStream { public long getTotalRead() { try { return inf.getBytesRead(); - } catch (Exception e) { + } catch (RuntimeException e) { return 0; } } @@ -116,7 +116,7 @@ class GunzipOutputStream extends InflaterOutputStream { public long getTotalExpanded() { try { return inf.getBytesWritten(); - } catch (Exception e) { + } catch (RuntimeException e) { // possible NPE in some implementations return 0; } @@ -128,7 +128,7 @@ class GunzipOutputStream extends InflaterOutputStream { public long getRemaining() { try { return inf.getRemaining(); - } catch (Exception e) { + } catch (RuntimeException e) { // possible NPE in some implementations return 0; } @@ -140,7 +140,7 @@ class GunzipOutputStream extends InflaterOutputStream { public boolean getFinished() { try { return inf.finished(); - } catch (Exception e) { + } catch (RuntimeException e) { // possible NPE in some implementations return true; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 7c0062075..e8680e3d3 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -1873,7 +1873,7 @@ public class I2PTunnel extends EventDispatcherImpl implements Logging { try { result.fromByteArray(content); return result; - } catch (Exception ex) { + } catch (RuntimeException ex) { if (log.shouldLog(Log.INFO)) log.info("File is not a binary destination - trying base64"); try { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java index 93785e326..4b1284cfe 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java @@ -3,6 +3,7 @@ */ package net.i2p.i2ptunnel; +import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import java.util.ArrayList; @@ -10,6 +11,7 @@ import java.util.List; import java.util.Properties; import java.util.StringTokenizer; +import net.i2p.I2PException; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketAddress; import net.i2p.data.Destination; @@ -122,7 +124,17 @@ public class I2PTunnelClient extends I2PTunnelClientBase { // we are called from an unlimited thread pool, so run inline //t.start(); t.run(); - } catch (Exception ex) { + } catch (IOException ex) { + if (_log.shouldLog(Log.INFO)) + _log.info("Error connecting", ex); + //l.log("Error connecting: " + ex.getMessage()); + closeSocket(s); + if (i2ps != null) { + synchronized (sockLock) { + mySockets.remove(sockLock); + } + } + } catch (I2PException ex) { if (_log.shouldLog(Log.INFO)) _log.info("Error connecting", ex); //l.log("Error connecting: " + ex.getMessage()); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 4183ce399..19ebd8b7c 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -414,7 +414,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn _log.debug(getPrefix(requestId) + "First line [" + line + "]"); } - String[] params = line.split(" ", 3); + String[] params = DataHelper.split(line, " ", 3); if(params.length != 3) { break; } @@ -1252,7 +1252,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelHTTPClientBase implements Runn String s = getTunnel().getClientOptions().getProperty(PROP_SSL_OUTPROXIES); if (s == null) return null; - String[] p = s.split("[,; \r\n\t]"); + String[] p = DataHelper.split(s, "[,; \r\n\t]"); if (p.length == 0) return null; // todo doesn't check for "" diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java index 5e39cf3b8..e68e38d6b 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClientBase.java @@ -285,7 +285,7 @@ public abstract class I2PTunnelHTTPClientBase extends I2PTunnelClientBase implem // We send Accept-Charset: UTF-8 in the 407 so hopefully it comes back that way inside the B64 ? try { String dec = new String(decoded, "UTF-8"); - String[] parts = dec.split(":"); + String[] parts = DataHelper.split(dec, ":"); String user = parts[0]; String pw = parts[1]; // first try pw for that user diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index 35dd6f132..2ae6abba4 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -664,7 +664,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { */ @Override protected String filterResponseLine(String line) { - String[] s = line.split(" ", 3); + String[] s = DataHelper.split(line, " ", 3); if (s.length > 1 && (s[1].startsWith("3") || s[1].startsWith("5"))) _dataExpected = 0; @@ -742,7 +742,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { public long getTotalRead() { try { return def.getTotalIn(); - } catch (Exception e) { + } catch (RuntimeException e) { // j2se 1.4.2_08 on linux is sometimes throwing an NPE in the getTotalIn() implementation return 0; } @@ -750,7 +750,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { public long getTotalCompressed() { try { return def.getTotalOut(); - } catch (Exception e) { + } catch (RuntimeException e) { // j2se 1.4.2_08 on linux is sometimes throwing an NPE in the getTotalOut() implementation return 0; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index 7f4c2c22a..f53a72cd1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.Properties; import java.util.StringTokenizer; +import net.i2p.I2PException; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketAddress; import net.i2p.data.DataHelper; @@ -142,7 +143,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase { // we are called from an unlimited thread pool, so run inline //out.start(); out.run(); - } catch (Exception ex) { + } catch (IOException ex) { // generally NoRouteToHostException if (_log.shouldLog(Log.WARN)) _log.warn("Error connecting", ex); @@ -160,6 +161,23 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase { mySockets.remove(sockLock); } } + } catch (I2PException ex) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Error connecting", ex); + //l.log("Error connecting: " + ex.getMessage()); + try { + // Send a response so the user doesn't just see a disconnect + // and blame his router or the network. + String name = addr != null ? addr.getHostName() : "undefined"; + String msg = ":" + name + " 499 you :" + ex + "\r\n"; + s.getOutputStream().write(DataHelper.getUTF8(msg)); + } catch (IOException ioe) {} + closeSocket(s); + if (i2ps != null) { + synchronized (sockLock) { + mySockets.remove(sockLock); + } + } } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java index 2288c27ec..79d974e90 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java @@ -13,6 +13,7 @@ import java.util.Properties; import net.i2p.client.streaming.I2PSocket; import net.i2p.crypto.SHA256Generator; +import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.data.Hash; import net.i2p.data.Base32; @@ -277,7 +278,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable { //if (_log.shouldLog(Log.DEBUG)) // _log.debug("Got line: " + s); - String field[]=s.split(" ",5); + String field[] = DataHelper.split(s, " ", 5); String command; int idx=0; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java index 2ed668b7a..d8d9369a0 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelOutproxyRunner.java @@ -182,7 +182,7 @@ public class I2PTunnelOutproxyRunner extends I2PAppThread { } catch (IllegalStateException ise) { if (_log.shouldLog(Log.WARN)) _log.warn("gnu?", ise); - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.ERROR)) _log.error("Internal error", e); } finally { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java index 2acd7cfc8..b8bfdaebf 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java @@ -326,7 +326,7 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr // at net.i2p.i2ptunnel.I2PTunnelRunner.run(I2PTunnelRunner.java:167) if (_log.shouldLog(Log.WARN)) _log.warn("gnu?", ise); - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.ERROR)) _log.error("Internal error", e); } finally { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java index 76a52c32b..3b9217238 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelServer.java @@ -517,7 +517,7 @@ public class I2PTunnelServer extends I2PTunnelTask implements Runnable { break; } catch(SocketTimeoutException ste) { // ignored, we never set the timeout - } catch (Exception e) { + } catch (RuntimeException e) { // streaming borkage if (_log.shouldLog(Log.ERROR)) _log.error("Uncaught exception accepting", e); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java index dd59042d8..da615301e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2Ping.java @@ -19,6 +19,7 @@ import net.i2p.I2PException; import net.i2p.client.I2PSession; import net.i2p.client.I2PSessionException; import net.i2p.client.streaming.I2PSocketManager; +import net.i2p.data.DataHelper; import net.i2p.data.Destination; import net.i2p.util.EventDispatcher; import net.i2p.util.I2PAppThread; @@ -93,7 +94,7 @@ public class I2Ping extends I2PTunnelClientBase { int localPort = 0; int remotePort = 0; boolean error = false; - String[] argv = cmd.split(" "); + String[] argv = DataHelper.split(cmd, " "); Getopt g = new Getopt("ping", argv, "t:m:n:chl:f:p:"); int c; while ((c = g.getopt()) != -1) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index d5ca354c5..4a6e85211 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -230,7 +230,7 @@ public class TunnelController implements Logging { } try { doStartTunnel(); - } catch (Exception e) { + } catch (RuntimeException e) { _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 diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java index f5b434e3b..24ac12e61 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/I2PTunnelDCCClient.java @@ -6,6 +6,7 @@ package net.i2p.i2ptunnel.irc; import java.net.Socket; import java.io.IOException; +import net.i2p.I2PException; import net.i2p.client.streaming.I2PSocket; import net.i2p.client.streaming.I2PSocketManager; import net.i2p.client.streaming.I2PSocketOptions; @@ -80,7 +81,14 @@ public class I2PTunnelDCCClient extends I2PTunnelClientBase { // we are called from an unlimited thread pool, so run inline //t.start(); t.run(); - } catch (Exception ex) { + } catch (IOException ex) { + _log.error("Could not make DCC connection to " + _dest + ':' + _remotePort, ex); + closeSocket(s); + if (i2ps != null) { + try { i2ps.close(); } catch (IOException ioe) {} + } + notifyEvent(CONNECT_STOP_EVENT, Integer.valueOf(getLocalPort())); + } catch (I2PException ex) { _log.error("Could not make DCC connection to " + _dest + ':' + _remotePort, ex); closeSocket(s); if (i2ps != null) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/IRCFilter.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/IRCFilter.java index 3112c9dda..eef558837 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/IRCFilter.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/irc/IRCFilter.java @@ -33,7 +33,7 @@ abstract class IRCFilter { */ public static String inboundFilter(String s, StringBuffer expectedPong, DCCHelper helper) { - String field[]=s.split(" ",4); + String field[] = DataHelper.split(s, " ", 4); String command; int idx=0; final String[] allowedCommands = @@ -274,7 +274,7 @@ abstract class IRCFilter { */ public static String outboundFilter(String s, StringBuffer expectedPong, DCCHelper helper) { - String field[]=s.split(" ",3); + String field[] = DataHelper.split(s, " ",3); if(field[0].length()==0) return null; // W T F? @@ -420,7 +420,7 @@ abstract class IRCFilter { int ctcp = msg.indexOf(0x01); if (ctcp > 0) msg = msg.substring(0, ctcp); - String[] args = msg.split(" ", 5); + String[] args = DataHelper.split(msg, " ", 5); if (args.length <= 0) return null; String type = args[0]; @@ -512,7 +512,7 @@ abstract class IRCFilter { int ctcp = msg.indexOf(0x01); if (ctcp > 0) msg = msg.substring(0, ctcp); - String[] args = msg.split(" ", 5); + String[] args = DataHelper.split(msg, " ", 5); if (args.length <= 0) return null; String type = args[0]; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java index b2b38398e..eb481f6ea 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/ui/GeneralHelper.java @@ -9,6 +9,7 @@ import java.util.Properties; import java.util.TreeMap; import net.i2p.I2PAppContext; +import net.i2p.I2PException; import net.i2p.client.I2PClient; import net.i2p.crypto.SigType; import net.i2p.data.DataHelper; @@ -341,7 +342,8 @@ public class GeneralHelper { rv = pkf.getDestination(); if (rv != null) return rv; - } catch (Exception e) {} + } catch (I2PException e) { + } catch (IOException e) {} } } return null; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java index fb9b137b2..d960dc93a 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java @@ -8,8 +8,11 @@ package net.i2p.i2ptunnel.web; * */ +import java.io.IOException; import java.util.List; import java.util.Set; + +import net.i2p.I2PException; import net.i2p.crypto.SigType; import net.i2p.data.Base64; import net.i2p.data.DataHelper; @@ -87,7 +90,8 @@ public class EditBean extends IndexBean { //System.err.println("Signing " + spoof + " with " + Base64.encode(privKey.getData())); Signature sig = _context.dsa().sign(spoof.getBytes("UTF-8"), privKey); return Base64.encode(sig.getData()); - } catch (Exception e) {} + } catch (I2PException e) { + } catch (IOException e) {} } return ""; } 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 15eb3f29e..2f2509c08 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -9,12 +9,14 @@ package net.i2p.i2ptunnel.web; */ import java.io.File; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Properties; import net.i2p.I2PAppContext; +import net.i2p.I2PException; import net.i2p.app.ClientAppManager; import net.i2p.app.Outproxy; import net.i2p.data.Certificate; @@ -266,7 +268,7 @@ public class IndexBean { if (_action != null) { try { buf.append(processAction()).append('\n'); - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "Error processing " + _action, e); buf.append("Error: ").append(e.toString()).append('\n'); } @@ -972,7 +974,9 @@ public class IndexBean { PrivateKeyFile pkf = new PrivateKeyFile(keyFile); try { pkf.createIfAbsent(); - } catch (Exception e) { + } catch (I2PException e) { + return "Create private key file failed: " + e; + } catch (IOException e) { return "Create private key file failed: " + e; } switch (_certType) { @@ -1011,7 +1015,9 @@ public class IndexBean { try { pkf.write(); newdest = pkf.getDestination(); - } catch (Exception e) { + } catch (I2PException e) { + return "Modification failed: " + e; + } catch (IOException e) { return "Modification failed: " + e; } return "Destination modified - " + diff --git a/apps/jetty/build.xml b/apps/jetty/build.xml index 2fad37dfa..b1fdbcd46 100644 --- a/apps/jetty/build.xml +++ b/apps/jetty/build.xml @@ -149,9 +149,14 @@ + diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java index 1b67bd226..73ede8bb0 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketEepGet.java @@ -5,7 +5,8 @@ import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.UnknownHostException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Locale; import java.util.Properties; @@ -112,8 +113,8 @@ public class I2PSocketEepGet extends EepGet { if (_socket != null) try { _socket.close(); } catch (IOException ioe) {} try { - URL url = new URL(_actualURL); - if ("http".equals(url.getProtocol())) { + URI url = new URI(_actualURL); + if ("http".equals(url.getScheme())) { String host = url.getHost(); int port = url.getPort(); if (port <= 0 || port > 65535) @@ -123,13 +124,16 @@ public class I2PSocketEepGet extends EepGet { // Rewrite the url to strip out the /i2p/, // as the naming service accepts B64KEY (but not B64KEY.i2p atm) if ("i2p".equals(host)) { - String file = url.getFile(); + String file = url.getRawPath(); try { int slash = 1 + file.substring(1).indexOf("/"); host = file.substring(1, slash); _actualURL = "http://" + host + file.substring(slash); + String query = url.getRawQuery(); + if (query != null) + _actualURL = _actualURL + '?' + query; } catch (IndexOutOfBoundsException ioobe) { - throw new IOException("Bad /i2p/ format: " + _actualURL); + throw new MalformedURLException("Bad /i2p/ format: " + _actualURL); } } @@ -173,12 +177,14 @@ public class I2PSocketEepGet extends EepGet { opts.setPort(port); _socket = _socketManager.connect(dest, opts); } else { - throw new IOException("Unsupported protocol: " + _actualURL); + throw new MalformedURLException("Unsupported protocol: " + _actualURL); } - } catch (MalformedURLException mue) { - throw new IOException("Request URL is invalid: " + _actualURL); + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Bad URL"); + ioe.initCause(use); + throw ioe; } catch (I2PException ie) { - throw new IOException(ie.toString()); + throw new IOException("I2P error", ie); } _proxyIn = _socket.getInputStream(); @@ -202,10 +208,17 @@ public class I2PSocketEepGet extends EepGet { @Override protected String getRequest() throws IOException { StringBuilder buf = new StringBuilder(2048); - URL url = new URL(_actualURL); + URI url; + try { + url = new URI(_actualURL); + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Bad URL"); + ioe.initCause(use); + throw ioe; + } //String host = url.getHost(); - String path = url.getPath(); - String query = url.getQuery(); + String path = url.getRawPath(); + String query = url.getRawQuery(); if (query != null) path = path + '?' + query; if (!path.startsWith("/")) @@ -232,6 +245,8 @@ public class I2PSocketEepGet extends EepGet { if(!uaOverridden) buf.append("User-Agent: " + USER_AGENT + "\r\n"); buf.append("\r\n"); + if (_log.shouldDebug()) + _log.debug("Request: [" + buf.toString() + "]"); return buf.toString(); } @@ -264,7 +279,7 @@ public class I2PSocketEepGet extends EepGet { url = args[i]; } } - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); usage(); return; diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java index 91c18cfe4..4e6d3b51f 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java @@ -195,7 +195,9 @@ public class I2PSocketManagerFactory { ByteArrayOutputStream keyStream = new ByteArrayOutputStream(1024); try { client.createDestination(keyStream, getSigType(opts)); - } catch (Exception e) { + } catch (I2PException e) { + throw new I2PSessionException("Error creating keys", e); + } catch (IOException e) { throw new I2PSessionException("Error creating keys", e); } myPrivateKeyStream = new ByteArrayInputStream(keyStream.toByteArray()); diff --git a/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java b/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java index d85baadf5..35da6b387 100644 --- a/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java +++ b/apps/routerconsole/java/src/net/i2p/router/news/NewsManager.java @@ -10,13 +10,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.TimeZone; import net.i2p.I2PAppContext; +import net.i2p.app.ClientApp; import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppState; import static net.i2p.app.ClientAppState.*; -import net.i2p.router.app.RouterApp; +import net.i2p.data.DataHelper; import net.i2p.util.FileUtil; import net.i2p.util.Log; import net.i2p.util.TranslateReader; @@ -30,7 +30,7 @@ import org.cybergarage.xml.Node; * * @since 0.9.23 */ -public class NewsManager implements RouterApp { +public class NewsManager implements ClientApp { private final I2PAppContext _context; private final Log _log; @@ -233,9 +233,7 @@ public class NewsManager implements RouterApp { // Doesn't work if the date has a : in it, but SHORT hopefully does not DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = _context.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(_context)); try { Date date = fmt.parse(newsContent.substring(0, colon)); entry.updated = date.getTime(); diff --git a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java index 66799737d..5c800bf03 100644 --- a/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java +++ b/apps/routerconsole/java/src/net/i2p/router/update/NewsFetcher.java @@ -19,7 +19,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.StringTokenizer; -import java.util.TimeZone; import net.i2p.app.ClientAppManager; import net.i2p.crypto.SU3File; @@ -226,6 +225,18 @@ class NewsFetcher extends UpdateRunner { _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); return; } + if (!FileUtil.isPack200Supported()) { + String msg = _mgr._t("No Pack200 support in Java runtime."); + _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg); + _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); + return; + } + if (!ConfigUpdateHandler.USE_SU3_UPDATE) { + String msg = _mgr._t("No update certificates installed."); + _log.logAlways(Log.WARN, "Cannot update to version " + ver + ": " + msg); + _mgr.notifyVersionConstraint(this, _currentURI, ROUTER_SIGNED, "", ver, msg); + return; + } String minRouter = args.get(MIN_VERSION_KEY); if (minRouter != null) { if (VersionComparator.comp(RouterVersion.VERSION, minRouter) < 0) { @@ -252,7 +263,7 @@ class NewsFetcher extends UpdateRunner { // TODO clearnet URLs, notify with HTTP_CLEARNET and/or HTTPS_CLEARNET Map> sourceMap = new HashMap>(4); // Must do su3 first - if (ConfigUpdateHandler.USE_SU3_UPDATE) { + //if (ConfigUpdateHandler.USE_SU3_UPDATE) { sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED_SU3, "", HTTP)); addMethod(TORRENT, args.get(SU3_KEY), sourceMap); addMethod(HTTP_CLEARNET, args.get(CLEARNET_HTTP_SU3_KEY), sourceMap); @@ -261,14 +272,14 @@ class NewsFetcher extends UpdateRunner { _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED_SU3, "", sourceMap, ver, ""); sourceMap.clear(); - } - // now do sud/su2 - sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP)); - String key = FileUtil.isPack200Supported() ? SU2_KEY : SUD_KEY; - addMethod(TORRENT, args.get(key), sourceMap); + //} + // now do sud/su2 - DISABLED + //sourceMap.put(HTTP, _mgr.getUpdateURLs(ROUTER_SIGNED, "", HTTP)); + //String key = FileUtil.isPack200Supported() ? SU2_KEY : SUD_KEY; + //addMethod(TORRENT, args.get(key), sourceMap); // notify about all sources at once - _mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED, - "", sourceMap, ver, ""); + //_mgr.notifyVersionAvailable(this, _currentURI, ROUTER_SIGNED, + // "", sourceMap, ver, ""); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Our version is current"); @@ -415,9 +426,8 @@ class NewsFetcher extends UpdateRunner { if (_tempFile.exists() && _tempFile.length() > 0) { File from; - // TODO check magic number instead? - // But then a corrupt file would be displayed as-is... - if (url.endsWith(".su3") || url.contains(".su3?")) { + // sud/su2 disabled + //if (url.endsWith(".su3") || url.contains(".su3?")) { try { from = processSU3(); } catch (IOException ioe) { @@ -425,9 +435,9 @@ class NewsFetcher extends UpdateRunner { _tempFile.delete(); return; } - } else { - from = _tempFile; - } + //} else { + // from = _tempFile; + //} boolean copied = FileUtil.rename(from, _newsFile); _tempFile.delete(); if (copied) { @@ -579,9 +589,7 @@ class NewsFetcher extends UpdateRunner { return; DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = _context.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(_context)); for (NewsEntry e : entries) { if (e.title == null || e.content == null) continue; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java index 7870363b5..2218f06a7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/CSSHelper.java @@ -107,7 +107,7 @@ public class CSSHelper extends HelperBase { if (Integer.parseInt(r) < MIN_REFRESH) r = "" + MIN_REFRESH; _context.router().saveConfig(PROP_REFRESH, r); - } catch (Exception e) { + } catch (RuntimeException e) { } } @@ -117,7 +117,7 @@ public class CSSHelper extends HelperBase { try { if (Integer.parseInt(r) < MIN_REFRESH) r = "" + MIN_REFRESH; - } catch (Exception e) { + } catch (RuntimeException e) { r = "" + MIN_REFRESH; } return r; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index c3abb58f5..fbb94ddef 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -207,7 +207,7 @@ public class ConfigNetHelper extends HelperBase { configs = Collections.emptySet(); } else { configs = new HashSet(4); - String[] ca = cs.split("[,; \r\n\t]"); + String[] ca = DataHelper.split(cs, "[,; \r\n\t]"); for (int i = 0; i < ca.length; i++) { String c = ca[i]; if (c.length() > 0) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java index f7d03555e..ab5e83408 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigReseedHandler.java @@ -2,8 +2,8 @@ package net.i2p.router.web; import java.io.InputStream; import java.io.IOException; -import java.net.URL; -import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -37,10 +37,10 @@ public class ConfigReseedHandler extends FormHandler { addFormError(_t("You must enter a URL")); return; } - URL url; + URI url; try { - url = new URL(val); - } catch (MalformedURLException mue) { + url = new URI(val); + } catch (URISyntaxException mue) { addFormError(_t("Bad URL {0}", val)); return; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java index 7747d22b2..1f75c3c82 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigSummaryHandler.java @@ -108,7 +108,7 @@ public class ConfigSummaryHandler extends FormHandler { } } } else if (moving) { - String parts[] = _action.split("_"); + String parts[] = DataHelper.split(_action, "_"); try { int from = Integer.parseInt(parts[1]); int to = 0; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/EventLogHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/EventLogHelper.java index f42e1cd6e..01ac1614b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/EventLogHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/EventLogHelper.java @@ -12,7 +12,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; import java.util.TreeMap; import net.i2p.data.DataHelper; @@ -189,9 +188,7 @@ public class EventLogHelper extends FormHandler { SimpleDateFormat fmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = _context.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(_context)); List> entries = new ArrayList>(events.entrySet()); Collections.reverse(entries); @@ -202,7 +199,7 @@ public class EventLogHelper extends FormHandler { buf.append(fmt.format(new Date(time))); buf.append(""); if (isAll) { - String[] s = event.split(" ", 2); + String[] s = DataHelper.split(event, " ", 2); String xs = _xevents.get(s[0]); if (xs == null) xs = s[0]; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java index b6afcf5ca..f937acb27 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/HomeHelper.java @@ -135,8 +135,10 @@ public class HomeHelper extends HelperBase { return renderConfig(apps); } + private static final String SS = Character.toString(S); + static Collection buildApps(RouterContext ctx, String config) { - String[] args = config.split("" + S); + String[] args = DataHelper.split(config, SS); Set apps = new TreeSet(new AppComparator()); for (int i = 0; i < args.length - 3; i += 4) { String name = Messages.getString(args[i], ctx); @@ -149,7 +151,7 @@ public class HomeHelper extends HelperBase { } static Collection buildSearchApps(String config) { - String[] args = config.split("" + S); + String[] args = DataHelper.split(config, SS); Set apps = new TreeSet(new AppComparator()); for (int i = 0; i < args.length - 1; i += 2) { String name = args[i]; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java index 357887f9e..07dfa5854 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NewsFeedHelper.java @@ -4,7 +4,6 @@ import java.text.DateFormat; import java.util.Collections; import java.util.Date; import java.util.List; -import java.util.TimeZone; import net.i2p.I2PAppContext; import net.i2p.app.ClientAppManager; @@ -56,9 +55,7 @@ public class NewsFeedHelper extends HelperBase { if (!entries.isEmpty()) { DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = ctx.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(ctx)); int i = 0; for (NewsEntry entry : entries) { if (i++ < start) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java index 386eb664e..2af0d5df4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PluginStarter.java @@ -423,7 +423,7 @@ public class PluginStarter implements Runnable { addPath(f.toURI().toURL()); log.error("INFO: Adding translation plugin to classpath: " + f); added = true; - } catch (Exception e) { + } catch (RuntimeException e) { log.error("Plugin " + appName + " bad classpath element: " + f, e); } } @@ -961,7 +961,7 @@ public class PluginStarter implements Runnable { urls.add(f.toURI().toURL()); if (log.shouldLog(Log.WARN)) log.warn("INFO: Adding plugin to classpath: " + f); - } catch (Exception e) { + } catch (IOException e) { log.error("Plugin client " + clientName + " bad classpath element: " + f, e); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SearchHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SearchHelper.java index e04809d6f..b9e40f959 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SearchHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SearchHelper.java @@ -43,9 +43,11 @@ public class SearchHelper extends HelperBase { _query = s; } + private static final String SS = Character.toString(S); + private void buildEngineMap() { String config = _context.getProperty(PROP_ENGINES, ENGINES_DEFAULT); - String[] args = config.split("" + S); + String[] args = DataHelper.split(config, SS); for (int i = 0; i < args.length - 1; i += 2) { String name = args[i]; String url = args[i+1]; 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 002f7983b..710ce2753 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryBarRenderer.java @@ -9,7 +9,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; import net.i2p.app.ClientAppManager; import net.i2p.crypto.SigType; @@ -634,9 +633,7 @@ public class SummaryBarRenderer { buf.append("
    \n"); DateFormat fmt = DateFormat.getDateInstance(DateFormat.SHORT); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = _context.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(_context)); int i = 0; final int max = 2; for (NewsEntry entry : entries) { 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 7e97d9573..75a55709f 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -861,6 +861,8 @@ public class SummaryHelper extends HelperBase { public void storeNewsHelper(NewsHelper n) { _newshelper = n; } public NewsHelper getNewsHelper() { return _newshelper; } + private static final String SS = Character.toString(S); + public List getSummaryBarSections(String page) { String config = ""; if ("home".equals(page)) { @@ -870,7 +872,7 @@ public class SummaryHelper extends HelperBase { if (config == null) config = _context.getProperty(PROP_SUMMARYBAR + "default", DEFAULT_FULL); } - return Arrays.asList(config.split("" + S)); + return Arrays.asList(DataHelper.split(config, SS)); } static void saveSummaryBarSections(RouterContext ctx, String page, Map sections) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index e1e2edc53..de13a6112 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -84,7 +84,8 @@ public class UpdateHandler { } else if (ConfigUpdateHandler.USE_SU3_UPDATE) { update(ROUTER_SIGNED_SU3); } else { - update(ROUTER_SIGNED); + // disabled, shouldn't get here + //update(ROUTER_SIGNED); } } } diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java index 89310ebda..7473bb79c 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/I2PSocketManagerFull.java @@ -9,6 +9,7 @@ import java.net.NoRouteToHostException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketTimeoutException; +import java.security.GeneralSecurityException; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -259,7 +260,13 @@ public class I2PSocketManagerFull implements I2PSocketManager { Certificate.NULL_CERT.writeBytes(keyStream); priv.writeBytes(keyStream); keys[1].writeBytes(keyStream); // signing priv - } catch (Exception e) { + } catch (GeneralSecurityException e) { + throw new I2PSessionException("Error creating keys", e); + } catch (I2PException e) { + throw new I2PSessionException("Error creating keys", e); + } catch (IOException e) { + throw new I2PSessionException("Error creating keys", e); + } catch (RuntimeException e) { throw new I2PSessionException("Error creating keys", e); } privateKeyStream = new ByteArrayInputStream(keyStream.toByteArray()); diff --git a/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java b/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java index a872b2d77..a887dc3d2 100644 --- a/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java +++ b/apps/streaming/java/src/net/i2p/client/streaming/impl/Packet.java @@ -585,7 +585,7 @@ class Packet { cur += 4; setAckThrough(DataHelper.fromLong(buffer, cur, 4)); cur += 4; - int numNacks = (int)DataHelper.fromLong(buffer, cur, 1); + int numNacks = buffer[cur] & 0xff; cur++; if (length < 22 + numNacks*4) throw new IllegalArgumentException("Too small with " + numNacks + " nacks: " + length); @@ -599,7 +599,7 @@ class Packet { } else { setNacks(null); } - setResendDelay((int)DataHelper.fromLong(buffer, cur, 1)); + setResendDelay(buffer[cur] & 0xff); cur++; setFlags((int)DataHelper.fromLong(buffer, cur, 2)); cur += 2; diff --git a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java index 360310682..205fcc8a7 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/AddressbookBean.java @@ -164,7 +164,7 @@ public class AddressbookBean extends BaseBean message = generateLoadMessage(); } - catch (Exception e) { + catch (IOException e) { warn(e); } finally { if (fis != null) @@ -316,7 +316,7 @@ public class AddressbookBean extends BaseBean try { save(); message += "
    " + _t("Address book saved."); - } catch (Exception e) { + } catch (IOException e) { warn(e); message += "
    " + _t("ERROR: Could not write addressbook file."); } diff --git a/apps/susidns/src/java/src/i2p/susi/dns/FormatDate.java b/apps/susidns/src/java/src/i2p/susi/dns/FormatDate.java index ad576dfb0..c7604a213 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/FormatDate.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/FormatDate.java @@ -2,9 +2,9 @@ package i2p.susi.dns; import java.util.Date; import java.text.DateFormat; -import java.util.TimeZone; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; /** * Format a date in local time zone @@ -17,9 +17,7 @@ public abstract class FormatDate static { DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = I2PAppContext.getGlobalContext().getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(I2PAppContext.getGlobalContext())); _dateFormat = fmt; } diff --git a/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java b/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java index 14eaebbd7..0fd326201 100644 --- a/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java +++ b/apps/susidns/src/java/src/i2p/susi/dns/NamingServiceBean.java @@ -205,7 +205,7 @@ public class NamingServiceBean extends AddressbookBean message = generateLoadMessage(); } - catch (Exception e) { + catch (RuntimeException e) { warn(e); } if( message.length() > 0 ) diff --git a/apps/susimail/src/src/i2p/susi/util/Config.java b/apps/susimail/src/src/i2p/susi/util/Config.java index a84ccede4..26171e87f 100644 --- a/apps/susimail/src/src/i2p/susi/util/Config.java +++ b/apps/susimail/src/src/i2p/susi/util/Config.java @@ -98,7 +98,7 @@ public class Config { try { iv = Config.class.getResourceAsStream("/susimail.properties"); properties.load(iv); - } catch (Exception e) { + } catch (IOException e) { Debug.debug(Debug.ERROR, "Could not open WEB-INF/classes/susimail.properties (possibly in jar), reason: " + e); } finally { if(iv != null) try { iv.close(); } catch(IOException ioe) {} @@ -109,7 +109,7 @@ public class Config { config = new OrderedProperties(); DataHelper.loadProps(config, cfg); } - } catch (Exception e) { + } catch (IOException e) { Debug.debug(Debug.ERROR, "Could not open susimail.config, reason: " + e); } } diff --git a/apps/susimail/src/src/i2p/susi/webmail/Mail.java b/apps/susimail/src/src/i2p/susi/webmail/Mail.java index 8632ac9c4..c184831c3 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/Mail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/Mail.java @@ -42,6 +42,7 @@ import java.util.Locale; import java.util.TimeZone; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; /** * data structure to hold a single message, mostly used with folder view and sorting @@ -126,7 +127,7 @@ class Mail { part = new MailPart(rb); } catch (DecodingException de) { Debug.debug(Debug.ERROR, "Decode error: " + de); - } catch (Exception e) { + } catch (RuntimeException e) { Debug.debug(Debug.ERROR, "Parse error: " + e); } } @@ -190,7 +191,7 @@ class Mail { address.indexOf( "\r" ) != -1 ) return false; - String[] tokens = address.split( "[ \t]+" ); + String[] tokens = DataHelper.split(address, "[ \t]+"); int addresses = 0; @@ -208,7 +209,7 @@ class Mail { */ public static String getAddress(String address ) { - String[] tokens = address.split( "[ \t]+" ); + String[] tokens = DataHelper.split(address, "[ \t]+"); for( int i = 0; i < tokens.length; i++ ) { if( tokens[i].matches( "^[^@< \t]+@[^> \t]+$" ) ) @@ -232,7 +233,7 @@ class Mail { public static boolean getRecipientsFromList( ArrayList recipients, String text, boolean ok ) { if( text != null && text.length() > 0 ) { - String[] ccs = text.split( "," ); + String[] ccs = DataHelper.split(text, ","); for( int i = 0; i < ccs.length; i++ ) { String recipient = ccs[i].trim(); if( validateAddress( recipient ) ) { @@ -275,12 +276,9 @@ class Mail { DateFormat localDateFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); DateFormat longLocalDateFormatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = I2PAppContext.getGlobalContext().getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) { - TimeZone tz = TimeZone.getTimeZone(systemTimeZone); - localDateFormatter.setTimeZone(tz); - longLocalDateFormatter.setTimeZone(tz); - } + TimeZone tz = DataHelper.getSystemTimeZone(I2PAppContext.getGlobalContext()); + localDateFormatter.setTimeZone(tz); + longLocalDateFormatter.setTimeZone(tz); DateFormat mailDateFormatter = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH ); error = ""; diff --git a/apps/susimail/src/src/i2p/susi/webmail/MailPart.java b/apps/susimail/src/src/i2p/susi/webmail/MailPart.java index 0ec32abe9..ff348a502 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/MailPart.java +++ b/apps/susimail/src/src/i2p/susi/webmail/MailPart.java @@ -79,7 +79,7 @@ class MailPart { beginBody = bb; ReadBuffer decodedHeaders = EncodingFactory.getEncoding( "HEADERLINE" ).decode( buffer.content, begin, beginBody - begin ); - headerLines = new String( decodedHeaders.content, decodedHeaders.offset, decodedHeaders.length ).split( "\r\n" ); + headerLines = DataHelper.split(new String(decodedHeaders.content, decodedHeaders.offset, decodedHeaders.length), "\r\n"); String boundary = null; String x_encoding = null; diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java index 9ff4b933b..bdcab5e89 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java @@ -614,7 +614,7 @@ public class WebMail extends HttpServlet showBody = false; reason = _t("Charset \\''{0}\\'' not supported.", quoteHTML( mailPart.charset )) + br; } - catch (Exception e1) { + catch (IOException e1) { showBody = false; reason += _t("Part ({0}) not shown, because of {1}", ident, e1.toString()) + br; } @@ -996,7 +996,7 @@ public class WebMail extends HttpServlet PrintWriter pw2 = new PrintWriter( text2 ); showPart( pw2, part, 0, TEXT_ONLY ); pw2.flush(); - String[] lines = text2.toString().split( "\r\n" ); + String[] lines = DataHelper.split(text2.toString(), "\r\n"); for( int i = 0; i < lines.length; i++ ) pw.println( "> " + lines[i] ); pw.flush(); diff --git a/apps/susimail/src/src/i2p/susi/webmail/encoding/DecodingException.java b/apps/susimail/src/src/i2p/susi/webmail/encoding/DecodingException.java index d0d89dd00..46277d7e5 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/encoding/DecodingException.java +++ b/apps/susimail/src/src/i2p/susi/webmail/encoding/DecodingException.java @@ -23,10 +23,12 @@ */ package i2p.susi.webmail.encoding; +import java.io.IOException; + /** * @author susi */ -public class DecodingException extends Exception { +public class DecodingException extends IOException { private static final long serialVersionUID = 1L; public DecodingException( String msg ) { diff --git a/apps/susimail/src/src/i2p/susi/webmail/encoding/HeaderLine.java b/apps/susimail/src/src/i2p/susi/webmail/encoding/HeaderLine.java index 4ed370dd2..e7db3672d 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/encoding/HeaderLine.java +++ b/apps/susimail/src/src/i2p/susi/webmail/encoding/HeaderLine.java @@ -233,7 +233,9 @@ public class HeaderLine implements Encoding { length -= distance; lastCharWasQuoted = true; continue; - } catch (Exception e1) { + } catch (IOException e1) { + Debug.debug(Debug.ERROR, e1.toString()); + } catch (RuntimeException e1) { Debug.debug(Debug.ERROR, e1.toString()); } } diff --git a/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java b/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java index 046dcbef5..fc4757735 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java +++ b/apps/susimail/src/src/i2p/susi/webmail/smtp/SMTPClient.java @@ -210,7 +210,7 @@ public class SMTPClient { try { socket = new Socket( host, port ); - } catch (Exception e) { + } catch (IOException e) { error += _t("Cannot connect") + ": " + e.getMessage() + '\n'; ok = false; } @@ -282,7 +282,7 @@ public class SMTPClient { error += e.getMessage(); } if( !mailSent && lastResponse.length() > 0 ) { - String[] lines = lastResponse.split( "\r" ); + String[] lines = DataHelper.split(lastResponse, "\r"); for( int i = 0; i < lines.length; i++ ) error += lines[i] + '\n'; } diff --git a/apps/systray/java/build.xml b/apps/systray/java/build.xml index 9fccf66fc..c5eb70731 100644 --- a/apps/systray/java/build.xml +++ b/apps/systray/java/build.xml @@ -5,11 +5,26 @@ + + + + + + + + + + + + - + done) break; try { @@ -172,9 +171,9 @@ public class UrlLauncher implements ClientApp { * @return true if the operation was successful, otherwise * false. * - * @throws Exception + * @throws IOException */ - public boolean openUrl(String url) throws Exception { + public boolean openUrl(String url) throws IOException { waitForServer(url); if (validateUrlFormat(url)) { String cbrowser = _context.getProperty(PROP_BROWSER); @@ -218,7 +217,7 @@ public class UrlLauncher implements ClientApp { // No worries. } foo.delete(); - } catch (Exception e) { + } catch (IOException e) { // Defaults to IE. } finally { if (bufferedReader != null) @@ -247,9 +246,9 @@ public class UrlLauncher implements ClientApp { * @return true if the operation was successful, * otherwise false. * - * @throws Exception + * @throws IOException */ - public boolean openUrl(String url, String browser) throws Exception { + public boolean openUrl(String url, String browser) throws IOException { waitForServer(url); if (validateUrlFormat(url)) { if (_shellCommand.executeSilentAndWaitTimed(browser + " " + url, 5)) @@ -261,8 +260,8 @@ public class UrlLauncher implements ClientApp { private static boolean validateUrlFormat(String urlString) { try { // just to check validity - new URL(urlString); - } catch (MalformedURLException e) { + new URI(urlString); + } catch (URISyntaxException e) { return false; } return true; @@ -290,7 +289,7 @@ public class UrlLauncher implements ClientApp { String url = _args[0]; openUrl(url); changeState(STOPPED); - } catch (Exception e) { + } catch (IOException e) { changeState(CRASHED, e); } } @@ -355,6 +354,6 @@ public class UrlLauncher implements ClientApp { launcher.openUrl(args[0]); else launcher.openUrl("http://127.0.0.1:7657/index.jsp"); - } catch (Exception e) {} + } catch (IOException e) {} } } diff --git a/build.xml b/build.xml index 9544491b5..1963a9d91 100644 --- a/build.xml +++ b/build.xml @@ -868,6 +868,21 @@ + + + + + + + + + + + + + + + @@ -1450,9 +1465,7 @@ diff --git a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java index 046683ea4..13d805619 100644 --- a/core/java/src/net/i2p/client/impl/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/impl/I2PSessionImpl.java @@ -862,7 +862,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 if ((duration > 100) && _log.shouldLog(Log.INFO)) _log.info("Message availability notification for " + msgId.intValue() + " took " + duration + " to " + _sessionListener); - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "Error notifying app of message availability", e); } } else { diff --git a/core/java/src/net/i2p/client/impl/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/impl/I2PSessionMuxedImpl.java index 07003ae2d..9b6f1ff0c 100644 --- a/core/java/src/net/i2p/client/impl/I2PSessionMuxedImpl.java +++ b/core/java/src/net/i2p/client/impl/I2PSessionMuxedImpl.java @@ -399,7 +399,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 { try { _demultiplexer.messageAvailable(I2PSessionMuxedImpl.this, msg.id, msg.size, msg.proto, msg.fromPort, msg.toPort); - } catch (Exception e) { + } catch (RuntimeException e) { _log.error("Error notifying app of message availability", e); } } diff --git a/core/java/src/net/i2p/client/naming/SingleFileNamingService.java b/core/java/src/net/i2p/client/naming/SingleFileNamingService.java index 219c61bbc..38a174b7e 100644 --- a/core/java/src/net/i2p/client/naming/SingleFileNamingService.java +++ b/core/java/src/net/i2p/client/naming/SingleFileNamingService.java @@ -91,7 +91,7 @@ public class SingleFileNamingService extends NamingService { key = getKey(hostname.substring(4)); if (key != null) return lookupBase64(key); - } catch (Exception ioe) { + } catch (IOException ioe) { if (_file.exists()) _log.error("Error loading hosts file " + _file, ioe); else if (_log.shouldLog(Log.WARN)) @@ -123,7 +123,7 @@ public class SingleFileNamingService extends NamingService { return line.substring(0, split); } return null; - } catch (Exception ioe) { + } catch (IOException ioe) { if (_file.exists()) _log.error("Error loading hosts file " + _file, ioe); else if (_log.shouldLog(Log.WARN)) diff --git a/core/java/src/net/i2p/crypto/DSAEngine.java b/core/java/src/net/i2p/crypto/DSAEngine.java index d7dfe657a..76f2004f8 100644 --- a/core/java/src/net/i2p/crypto/DSAEngine.java +++ b/core/java/src/net/i2p/crypto/DSAEngine.java @@ -257,7 +257,7 @@ public class DSAEngine { _log.warn("Took too long to verify the signature (" + diff + "ms)"); } return ok; - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "Error verifying the signature", e); return false; } diff --git a/core/java/src/net/i2p/crypto/ECConstants.java b/core/java/src/net/i2p/crypto/ECConstants.java index d9b111e23..8bca0b0ac 100644 --- a/core/java/src/net/i2p/crypto/ECConstants.java +++ b/core/java/src/net/i2p/crypto/ECConstants.java @@ -3,6 +3,7 @@ package net.i2p.crypto; import java.lang.reflect.Constructor; import java.math.BigInteger; import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; import java.security.Provider; import java.security.Security; import java.security.spec.ECField; @@ -278,7 +279,7 @@ class ECConstants { AlgorithmParameters ap; try { ap = AlgorithmParameters.getInstance("EC"); - } catch (Exception e) { + } catch (GeneralSecurityException e) { if (BC_AVAILABLE) { log("Named curve " + name + " is not available, trying BC", e); ap = AlgorithmParameters.getInstance("EC", "BC"); @@ -292,7 +293,7 @@ class ECConstants { ECParameterSpec rv = ap.getParameterSpec(ECParameterSpec.class); log("Named curve " + name + " loaded"); return rv; - } catch (Exception e) { + } catch (GeneralSecurityException e) { log("Named curve " + name + " is not available", e); return null; } diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java index 126a06a36..0fe652bb2 100644 --- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java @@ -327,12 +327,12 @@ public class ElGamalAESEngine { //ByteArrayInputStream bais = new ByteArrayInputStream(decrypted); int cur = 0; long numTags = DataHelper.fromLong(decrypted, cur, 2); - if ((numTags < 0) || (numTags > MAX_TAGS_RECEIVED)) throw new Exception("Invalid number of session tags"); + if ((numTags < 0) || (numTags > MAX_TAGS_RECEIVED)) throw new IllegalArgumentException("Invalid number of session tags"); if (numTags > 0) tags = new ArrayList((int)numTags); cur += 2; //_log.debug("# tags: " + numTags); if (numTags * SessionTag.BYTE_LENGTH > decrypted.length - 2) { - throw new Exception("# tags: " + numTags + " is too many for " + (decrypted.length - 2)); + throw new IllegalArgumentException("# tags: " + numTags + " is too many for " + (decrypted.length - 2)); } for (int i = 0; i < numTags; i++) { byte tag[] = new byte[SessionTag.BYTE_LENGTH]; @@ -344,7 +344,7 @@ public class ElGamalAESEngine { cur += 4; //_log.debug("len: " + len); if ((len < 0) || (len > decrypted.length - cur - Hash.HASH_LENGTH - 1)) - throw new Exception("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")"); + throw new IllegalArgumentException("Invalid size of payload (" + len + ", remaining " + (decrypted.length-cur) +")"); //byte hashval[] = new byte[Hash.HASH_LENGTH]; //System.arraycopy(decrypted, cur, hashval, 0, Hash.HASH_LENGTH); //readHash = new Hash(); @@ -379,8 +379,8 @@ public class ElGamalAESEngine { return unencrData; } - throw new Exception("Hash does not match"); - } catch (Exception e) { + throw new RuntimeException("Hash does not match"); + } catch (RuntimeException e) { if (_log.shouldLog(Log.WARN)) _log.warn("Unable to decrypt AES block", e); return null; } diff --git a/core/java/src/net/i2p/crypto/EncType.java b/core/java/src/net/i2p/crypto/EncType.java index cb9c0ad96..fc07d5d5a 100644 --- a/core/java/src/net/i2p/crypto/EncType.java +++ b/core/java/src/net/i2p/crypto/EncType.java @@ -108,7 +108,7 @@ public enum EncType { return true; try { getParams(); - } catch (Exception e) { + } catch (InvalidParameterSpecException e) { return false; } return true; diff --git a/core/java/src/net/i2p/crypto/KeyGenerator.java b/core/java/src/net/i2p/crypto/KeyGenerator.java index 60742c2fb..c198d0b34 100644 --- a/core/java/src/net/i2p/crypto/KeyGenerator.java +++ b/core/java/src/net/i2p/crypto/KeyGenerator.java @@ -343,7 +343,7 @@ public class KeyGenerator { public static void main(String args[]) { try { main2(args); - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); } } @@ -381,7 +381,7 @@ public class KeyGenerator { try { System.out.println("Testing " + type); testSig(type, runs); - } catch (Exception e) { + } catch (GeneralSecurityException e) { System.out.println("error testing " + type); e.printStackTrace(); } diff --git a/core/java/src/net/i2p/crypto/KeyStoreUtil.java b/core/java/src/net/i2p/crypto/KeyStoreUtil.java index 06b73cea8..d994018cf 100644 --- a/core/java/src/net/i2p/crypto/KeyStoreUtil.java +++ b/core/java/src/net/i2p/crypto/KeyStoreUtil.java @@ -98,7 +98,8 @@ public class KeyStoreUtil { try { ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray()); success = addCerts(new File(System.getProperty("java.home"), "etc/security/cacerts"), ks) > 0; - } catch (Exception e) {} + } catch (IOException e) { + } catch (GeneralSecurityException e) {} } else { success = loadCerts(new File(System.getProperty("java.home"), "etc/security/cacerts.bks"), ks); } @@ -113,7 +114,8 @@ public class KeyStoreUtil { try { // must be initted ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray()); - } catch (Exception e) {} + } catch (IOException e) { + } catch (GeneralSecurityException e) {} error("All key store loads failed, will only load local certificates", null); } return ks; @@ -140,13 +142,15 @@ public class KeyStoreUtil { try { // not clear if null is allowed for password ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray()); - } catch (Exception foo) {} + } catch (IOException foo) { + } catch (GeneralSecurityException e) {} return false; } catch (IOException ioe) { error("KeyStore load error, no default keys: " + file.getAbsolutePath(), ioe); try { ks.load(null, DEFAULT_KEYSTORE_PASSWORD.toCharArray()); - } catch (Exception foo) {} + } catch (IOException foo) { + } catch (GeneralSecurityException e) {} return false; } finally { try { if (fis != null) fis.close(); } catch (IOException foo) {} @@ -171,7 +175,7 @@ public class KeyStoreUtil { count++; } } - } catch (Exception foo) {} + } catch (GeneralSecurityException e) {} return count; } @@ -316,7 +320,10 @@ public class KeyStoreUtil { error("Not overwriting key " + alias + ", already exists in " + ks, null); return false; } - } catch (Exception e) { + } catch (IOException e) { + error("Not overwriting key \"" + alias + "\", already exists in " + ks, e); + return false; + } catch (GeneralSecurityException e) { error("Not overwriting key \"" + alias + "\", already exists in " + ks, e); return false; } @@ -354,7 +361,10 @@ public class KeyStoreUtil { success = getPrivateKey(ks, ksPW, alias, keyPW) != null; if (!success) error("Key gen failed to get private key", null); - } catch (Exception e) { + } catch (IOException e) { + error("Key gen failed to get private key", e); + success = false; + } catch (GeneralSecurityException e) { error("Key gen failed to get private key", e); success = false; } diff --git a/core/java/src/net/i2p/crypto/SigType.java b/core/java/src/net/i2p/crypto/SigType.java index 48ad93e0a..05dd1906e 100644 --- a/core/java/src/net/i2p/crypto/SigType.java +++ b/core/java/src/net/i2p/crypto/SigType.java @@ -1,5 +1,6 @@ package net.i2p.crypto; +import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Signature; @@ -215,7 +216,9 @@ public enum SigType { } getDigestInstance(); getHashInstance(); - } catch (Exception e) { + } catch (GeneralSecurityException e) { + return false; + } catch (RuntimeException e) { return false; } return true; diff --git a/core/java/src/net/i2p/crypto/TrustedUpdate.java b/core/java/src/net/i2p/crypto/TrustedUpdate.java index b365a662a..5174292a2 100644 --- a/core/java/src/net/i2p/crypto/TrustedUpdate.java +++ b/core/java/src/net/i2p/crypto/TrustedUpdate.java @@ -344,7 +344,11 @@ riCe6OlAEiNpcc6mMyIYYWFICbrDFTrDR3wXqwc/Jkcx6L5VVWoagpSzbo3yGhc= System.out.println("\r\nPrivate key written to: " + privateKeyFile); System.out.println("Public key written to: " + publicKeyFile); System.out.println("\r\nPublic key: " + signingPublicKey.toBase64() + "\r\n"); - } catch (Exception e) { + } catch (IOException e) { + System.err.println("Error writing keys:"); + e.printStackTrace(); + return false; + } catch (DataFormatException e) { System.err.println("Error writing keys:"); e.printStackTrace(); return false; @@ -758,7 +762,7 @@ riCe6OlAEiNpcc6mMyIYYWFICbrDFTrDR3wXqwc/Jkcx6L5VVWoagpSzbo3yGhc= bytesToSignInputStream = new SequenceInputStream(versionHeaderInputStream, fileInputStream); signature = _context.dsa().sign(bytesToSignInputStream, signingPrivateKey); - } catch (Exception e) { + } catch (IOException e) { if (_log.shouldLog(Log.ERROR)) _log.error("Error signing", e); diff --git a/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java b/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java index 268005ed7..ec81b5d40 100644 --- a/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java +++ b/core/java/src/net/i2p/crypto/eddsa/math/GroupElement.java @@ -722,7 +722,7 @@ public class GroupElement implements Serializable { if (!this.repr.equals(ge.repr)) { try { ge = ge.toRep(this.repr); - } catch (Exception e) { + } catch (RuntimeException e) { return false; } } diff --git a/core/java/src/net/i2p/data/Certificate.java b/core/java/src/net/i2p/data/Certificate.java index aa2624b8a..aefc34ce6 100644 --- a/core/java/src/net/i2p/data/Certificate.java +++ b/core/java/src/net/i2p/data/Certificate.java @@ -215,7 +215,7 @@ public class Certificate extends DataStructureImpl { throw new DataFormatException("Cert is too small [" + source.length + " off=" + offset + "]"); int cur = offset; - _type = (int)DataHelper.fromLong(source, cur, 1); + _type = source[cur] & 0xff; cur++; int length = (int)DataHelper.fromLong(source, cur, 2); cur += 2; diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 85bc2dee8..ee78a95c6 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -37,6 +37,9 @@ import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.Properties; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; import java.util.zip.Deflater; import net.i2p.I2PAppContext; @@ -1615,11 +1618,11 @@ public class DataHelper { * NOTE: formatDuration2() recommended in most cases for readability */ public static String formatSize(long bytes) { - double val = bytes; + float val = bytes; int scale = 0; - while (val >= 1024) { + while (val >= 1024.0f) { scale++; - val /= 1024; + val /= 1024.0f; } DecimalFormat fmt = new DecimalFormat("##0.00"); @@ -1888,4 +1891,54 @@ public class DataHelper { } return rv; } + + /** + * Same as s.split(regex) but caches the compiled pattern for speed. + * This saves about 10 microseconds (Bulldozer) on subsequent invocations. + * + * @param s non-null + * @param regex non-null + * @throws java.util.regex.PatternSyntaxException unchecked + * @since 0.9.24 + */ + public static String[] split(String s, String regex) { + return split(s, regex, 0); + } + + private static final ConcurrentHashMap patterns = new ConcurrentHashMap(); + + /** + * Same as s.split(regex, limit) but caches the compiled pattern for speed. + * This saves about 10 microseconds (Bulldozer) on subsequent invocations. + * + * @param s non-null + * @param regex non-null + * @param limit result threshold + * @throws java.util.regex.PatternSyntaxException unchecked + * @since 0.9.24 + */ + public static String[] split(String s, String regex, int limit) { + Pattern p = patterns.get(regex); + if (p == null) { + p = Pattern.compile(regex); + patterns.putIfAbsent(regex, p); + } + return p.split(s, limit); + } + + /** + * The system's time zone, which is probably different from the + * JVM time zone, because Router changes the JVM default to GMT. + * It saves the old default in the context properties where we can get it. + * Use this to format a time in local time zone with DateFormat.setTimeZone(). + * + * @return non-null + * @since 0.9.24 + */ + public static TimeZone getSystemTimeZone(I2PAppContext ctx) { + String systemTimeZone = ctx.getProperty("i2p.systemTimeZone"); + if (systemTimeZone != null) + return TimeZone.getTimeZone(systemTimeZone); + return TimeZone.getDefault(); + } } diff --git a/core/java/src/net/i2p/data/PrivateKeyFile.java b/core/java/src/net/i2p/data/PrivateKeyFile.java index f42d8da15..b77fd1350 100644 --- a/core/java/src/net/i2p/data/PrivateKeyFile.java +++ b/core/java/src/net/i2p/data/PrivateKeyFile.java @@ -9,6 +9,7 @@ import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; import java.util.Locale; import java.util.Map; import java.util.Properties; @@ -174,7 +175,10 @@ public class PrivateKeyFile { pkf.write(); verifySignature(pkf.getDestination()); } - } catch (Exception e) { + } catch (I2PException e) { + e.printStackTrace(); + System.exit(1); + } catch (IOException e) { e.printStackTrace(); System.exit(1); } @@ -358,7 +362,7 @@ public class PrivateKeyFile { HashCash hc; try { hc = HashCash.mintCash(resource, effort); - } catch (Exception e) { + } catch (NoSuchAlgorithmException e) { return null; } System.out.println("Generation took: " + DataHelper.formatDuration(System.currentTimeMillis() - begin)); @@ -391,7 +395,9 @@ public class PrivateKeyFile { Destination d2; try { d2 = pkf2.getDestination(); - } catch (Exception e) { + } catch (I2PException e) { + return null; + } catch (IOException e) { return null; } if (d2 == null) @@ -500,7 +506,7 @@ public class PrivateKeyFile { long low = Long.MAX_VALUE; try { low = HashCash.estimateTime(hashEffort); - } catch (Exception e) {} + } catch (NoSuchAlgorithmException e) {} // takes a lot longer than the estimate usually... // maybe because the resource string is much longer than used in the estimate? return "It is estimated that generating a HashCash Certificate with value " + hashEffort + diff --git a/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java b/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java index 4dfbb8501..4bfdbc158 100644 --- a/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java +++ b/core/java/src/net/i2p/data/i2cp/I2CPMessageReader.java @@ -160,7 +160,7 @@ public class I2CPMessageReader { public void run() { try { run2(); - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "Uncaught I2CP error", e); _listener.readError(I2CPMessageReader.this, e); cancelRunner(); @@ -193,7 +193,7 @@ public class I2CPMessageReader { } catch (OutOfMemoryError oom) { // ooms seen here... maybe log and keep going? throw oom; - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "Unhandled error reading I2CP stream", e); _listener.disconnected(I2CPMessageReader.this); cancelRunner(); diff --git a/core/java/src/net/i2p/stat/BufferedStatLog.java b/core/java/src/net/i2p/stat/BufferedStatLog.java index 7c9b7b723..5734e8948 100644 --- a/core/java/src/net/i2p/stat/BufferedStatLog.java +++ b/core/java/src/net/i2p/stat/BufferedStatLog.java @@ -145,7 +145,7 @@ public class BufferedStatLog implements StatLog { if (_log.shouldLog(Log.DEBUG)) _log.debug("writing " + writeStart +"->"+ writeEnd); writeEvents(writeStart, writeEnd); - } catch (Exception e) { + } catch (RuntimeException e) { _log.error("error writing " + writeStart +"->"+ writeEnd, e); } } diff --git a/core/java/src/net/i2p/util/EepGet.java b/core/java/src/net/i2p/util/EepGet.java index 88cae89fe..19816bb41 100644 --- a/core/java/src/net/i2p/util/EepGet.java +++ b/core/java/src/net/i2p/util/EepGet.java @@ -15,7 +15,8 @@ import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.Socket; import java.net.UnknownHostException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Date; @@ -272,7 +273,7 @@ public class EepGet { break; } // switch } // while - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); error = true; } @@ -321,17 +322,17 @@ public class EepGet { * @return a filename to save the resource as on local filesystem */ public static String suggestName(String url) { - URL nameURL = null; // URL object + URI nameURL = null; String name; // suggested name try { - nameURL = new URL(url); - } catch (MalformedURLException e) { + nameURL = new URI(url); + } catch (URISyntaxException e) { System.err.println("Please enter a properly formed URL."); System.exit(1); } - String path = nameURL.getPath(); // discard any URI queries + String path = nameURL.getRawPath(); // discard any URI queries // if no file specified, eepget scrapes webpage - use domain as name Pattern slashes = Pattern.compile("/+"); @@ -722,24 +723,25 @@ public class EepGet { if (_redirectLocation != null) { // we also are here after a 407 - //try { + try { if (_redirectLocation.startsWith("http://")) { _actualURL = _redirectLocation; } else { // the Location: field has been required to be an absolute URI at least since // RFC 1945 (HTTP/1.0 1996), so it isn't clear what the point of this is. // This oddly adds a ":" even if no port, but that seems to work. - URL url = new URL(_actualURL); + URI url = new URI(_actualURL); if (_redirectLocation.startsWith("/")) _actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation; else // this blows up completely on a redirect to https://, for example _actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation; } - // an MUE is an IOE - //} catch (MalformedURLException mue) { - // throw new IOException("Redirected from an invalid URL"); - //} + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Redirected to invalid URL"); + ioe.initCause(use); + throw ioe; + } AuthState as = _authState; if (_responseCode == 407) { @@ -1131,7 +1133,7 @@ public class EepGet { private int handleStatus(String line) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Status line: [" + line.trim() + "]"); - String[] toks = line.split(" ", 3); + String[] toks = DataHelper.split(line, " ", 3); if (toks.length < 2) { if (_log.shouldLog(Log.WARN)) _log.warn("ERR: status "+ line); @@ -1226,9 +1228,9 @@ public class EepGet { if (_shouldProxy) { _proxy = InternalSocket.getSocket(_proxyHost, _proxyPort); } else { - //try { - URL url = new URL(_actualURL); - if ("http".equals(url.getProtocol())) { + try { + URI url = new URI(_actualURL); + if ("http".equals(url.getScheme())) { String host = url.getHost(); String hostlc = host.toLowerCase(Locale.US); if (hostlc.endsWith(".i2p")) @@ -1248,10 +1250,11 @@ public class EepGet { } else { throw new MalformedURLException("URL is not supported:" + _actualURL); } - // an MUE is an IOE - //} catch (MalformedURLException mue) { - // throw new IOException("Request URL is invalid"); - //} + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Request URL is invalid"); + ioe.initCause(use); + throw ioe; + } } _proxyIn = _proxy.getInputStream(); if (!(_proxy instanceof InternalSocket)) @@ -1273,13 +1276,20 @@ public class EepGet { boolean post = false; if ( (_postData != null) && (_postData.length() > 0) ) post = true; - URL url = new URL(_actualURL); + URI url; + try { + url = new URI(_actualURL); + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Bad URL"); + ioe.initCause(use); + throw ioe; + } String host = url.getHost(); if (host == null || host.length() <= 0) throw new MalformedURLException("Bad URL, no host"); int port = url.getPort(); - String path = url.getPath(); - String query = url.getQuery(); + String path = url.getRawPath(); + String query = url.getRawQuery(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Requesting " + _actualURL); // RFC 2616 sec 5.1.2 - full URL if proxied, absolute path only if not proxied diff --git a/core/java/src/net/i2p/util/EepHead.java b/core/java/src/net/i2p/util/EepHead.java index c1ddb6282..3c5331493 100644 --- a/core/java/src/net/i2p/util/EepHead.java +++ b/core/java/src/net/i2p/util/EepHead.java @@ -6,7 +6,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; -import java.net.URL; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import gnu.getopt.Getopt; @@ -107,7 +109,7 @@ public class EepHead extends EepGet { break; } // switch } // while - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); error = true; } @@ -176,24 +178,25 @@ public class EepHead extends EepGet { // Should we even follow redirects for HEAD? if (_redirectLocation != null) { - //try { + try { if (_redirectLocation.startsWith("http://")) { _actualURL = _redirectLocation; } else { // the Location: field has been required to be an absolute URI at least since // RFC 1945 (HTTP/1.0 1996), so it isn't clear what the point of this is. // This oddly adds a ":" even if no port, but that seems to work. - URL url = new URL(_actualURL); + URI url = new URI(_actualURL); if (_redirectLocation.startsWith("/")) _actualURL = "http://" + url.getHost() + ":" + url.getPort() + _redirectLocation; else // this blows up completely on a redirect to https://, for example _actualURL = "http://" + url.getHost() + ":" + url.getPort() + "/" + _redirectLocation; } - // an MUE is an IOE - //} catch (MalformedURLException mue) { - // throw new IOException("Redirected from an invalid URL"); - //} + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Redirected to invalid URL"); + ioe.initCause(use); + throw ioe; + } AuthState as = _authState; if (_responseCode == 407) { if (!_shouldProxy) @@ -252,11 +255,18 @@ public class EepHead extends EepGet { @Override protected String getRequest() throws IOException { StringBuilder buf = new StringBuilder(512); - URL url = new URL(_actualURL); + URI url; + try { + url = new URI(_actualURL); + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Bad URL"); + ioe.initCause(use); + throw ioe; + } String host = url.getHost(); int port = url.getPort(); - String path = url.getPath(); - String query = url.getQuery(); + String path = url.getRawPath(); + String query = url.getRawQuery(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Requesting " + _actualURL); // RFC 2616 sec 5.1.2 - full URL if proxied, absolute path only if not proxied diff --git a/core/java/src/net/i2p/util/FortunaRandomSource.java b/core/java/src/net/i2p/util/FortunaRandomSource.java index 9688e8764..e386e325c 100644 --- a/core/java/src/net/i2p/util/FortunaRandomSource.java +++ b/core/java/src/net/i2p/util/FortunaRandomSource.java @@ -11,6 +11,7 @@ package net.i2p.util; import gnu.crypto.prng.AsyncFortunaStandalone; +import java.io.IOException; import java.security.SecureRandom; import net.i2p.I2PAppContext; @@ -266,7 +267,7 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste synchronized(_fortuna) { _fortuna.addRandomBytes(data, offset, len); } - } catch (Exception e) { + } catch (RuntimeException e) { // AIOOBE seen, root cause unknown, ticket #1576 Log log = _context.logManager().getLog(FortunaRandomSource.class); log.warn("feedEntropy()", e); @@ -290,6 +291,6 @@ public class FortunaRandomSource extends RandomSource implements EntropyHarveste rand.nextBytes(buf); System.out.write(buf); } - } catch (Exception e) { e.printStackTrace(); } + } catch (IOException e) { e.printStackTrace(); } } } diff --git a/core/java/src/net/i2p/util/I2PSSLSocketFactory.java b/core/java/src/net/i2p/util/I2PSSLSocketFactory.java index 774415f4d..1b8342808 100644 --- a/core/java/src/net/i2p/util/I2PSSLSocketFactory.java +++ b/core/java/src/net/i2p/util/I2PSSLSocketFactory.java @@ -83,6 +83,7 @@ import javax.net.ssl.TrustManagerFactory; import net.i2p.I2PAppContext; import net.i2p.crypto.KeyStoreUtil; +import net.i2p.data.DataHelper; import org.apache.http.conn.ssl.DefaultHostnameVerifier; import org.apache.http.conn.util.PublicSuffixList; @@ -443,7 +444,7 @@ public class I2PSSLSocketFactory { try { if (line.charAt(0) == '#') continue; - String[] s = line.split(","); + String[] s = DataHelper.split(line, ","); String lc = s[0].toLowerCase(Locale.US); tlds.add(lc); i++; diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java index ca2476de8..94a39cf0c 100644 --- a/core/java/src/net/i2p/util/LogManager.java +++ b/core/java/src/net/i2p/util/LogManager.java @@ -22,7 +22,6 @@ import java.util.Map; import java.util.Properties; import java.util.Queue; import java.util.Set; -import java.util.TimeZone; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicInteger; @@ -479,9 +478,7 @@ public class LogManager implements Flushable { if (!format.equals("")) fmt.applyPattern(format); // the router sets the JVM time zone to UTC but saves the original here so we can get it - String systemTimeZone = _context.getProperty("i2p.systemTimeZone"); - if (systemTimeZone != null) - fmt.setTimeZone(TimeZone.getTimeZone(systemTimeZone)); + fmt.setTimeZone(DataHelper.getSystemTimeZone(_context)); _dateFormatPattern = format; _dateFormat = fmt; return true; diff --git a/core/java/src/net/i2p/util/LogWriterBase.java b/core/java/src/net/i2p/util/LogWriterBase.java index b9b98e10d..cc4fb93e6 100644 --- a/core/java/src/net/i2p/util/LogWriterBase.java +++ b/core/java/src/net/i2p/util/LogWriterBase.java @@ -75,7 +75,7 @@ abstract class LogWriterBase implements Runnable { if (_write && shouldReadConfig) rereadConfig(); } - } catch (Exception e) { + } catch (RuntimeException e) { System.err.println("Error writing the log: " + e); e.printStackTrace(); } diff --git a/core/java/src/net/i2p/util/NativeBigInteger.java b/core/java/src/net/i2p/util/NativeBigInteger.java index afb380cf9..96129b5ac 100644 --- a/core/java/src/net/i2p/util/NativeBigInteger.java +++ b/core/java/src/net/i2p/util/NativeBigInteger.java @@ -35,6 +35,7 @@ import freenet.support.CPUInformation.UnknownCPUException; import net.i2p.I2PAppContext; import net.i2p.crypto.CryptoConstants; +import net.i2p.data.DataHelper; /** *

    BigInteger that takes advantage of the jbigi library for the modPow operation, @@ -734,7 +735,7 @@ public class NativeBigInteger extends BigInteger { in = new BufferedReader(new InputStreamReader(new FileInputStream("/proc/cpuinfo"), "ISO-8859-1"), 4096); String line = null; while ( (line = in.readLine()) != null) { - String[] parts = line.split(":", 2); + String[] parts = DataHelper.split(line, ":", 2); if (parts.length < 2) continue; String key = parts[0].trim().toLowerCase(Locale.US); diff --git a/core/java/src/net/i2p/util/PartialEepGet.java b/core/java/src/net/i2p/util/PartialEepGet.java index baab6e039..9d853137d 100644 --- a/core/java/src/net/i2p/util/PartialEepGet.java +++ b/core/java/src/net/i2p/util/PartialEepGet.java @@ -6,7 +6,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Locale; import gnu.getopt.Getopt; @@ -106,7 +107,7 @@ public class PartialEepGet extends EepGet { break; } // switch } // while - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); error = true; } @@ -167,13 +168,20 @@ public class PartialEepGet extends EepGet { @Override protected String getRequest() throws IOException { StringBuilder buf = new StringBuilder(2048); - URL url = new URL(_actualURL); + URI url; + try { + url = new URI(_actualURL); + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Bad URL"); + ioe.initCause(use); + throw ioe; + } String host = url.getHost(); if (host == null || host.length() <= 0) throw new MalformedURLException("Bad URL, no host"); int port = url.getPort(); - String path = url.getPath(); - String query = url.getQuery(); + String path = url.getRawPath(); + String query = url.getRawQuery(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Requesting " + _actualURL); // RFC 2616 sec 5.1.2 - full URL if proxied, absolute path only if not proxied diff --git a/core/java/src/net/i2p/util/ResettableGZIPInputStream.java b/core/java/src/net/i2p/util/ResettableGZIPInputStream.java index 645bd29f3..13eecb518 100644 --- a/core/java/src/net/i2p/util/ResettableGZIPInputStream.java +++ b/core/java/src/net/i2p/util/ResettableGZIPInputStream.java @@ -124,7 +124,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream { public long getTotalRead() { try { return inf.getBytesRead(); - } catch (Exception e) { + } catch (RuntimeException e) { return 0; } } @@ -136,7 +136,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream { public long getTotalExpanded() { try { return inf.getBytesWritten(); - } catch (Exception e) { + } catch (RuntimeException e) { // possible NPE in some implementations return 0; } @@ -149,7 +149,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream { public long getRemaining() { try { return inf.getRemaining(); - } catch (Exception e) { + } catch (RuntimeException e) { // possible NPE in some implementations return 0; } @@ -162,7 +162,7 @@ public class ResettableGZIPInputStream extends InflaterInputStream { public boolean getFinished() { try { return inf.finished(); - } catch (Exception e) { + } catch (RuntimeException e) { // possible NPE in some implementations return true; } diff --git a/core/java/src/net/i2p/util/SSLEepGet.java b/core/java/src/net/i2p/util/SSLEepGet.java index 3a6e7ebd9..c62da0c12 100644 --- a/core/java/src/net/i2p/util/SSLEepGet.java +++ b/core/java/src/net/i2p/util/SSLEepGet.java @@ -46,7 +46,8 @@ import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.net.InetSocketAddress; import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.security.KeyStore; import java.security.GeneralSecurityException; import java.security.cert.CertificateException; @@ -179,7 +180,7 @@ public class SSLEepGet extends EepGet { break; } // switch } // while - } catch (Exception e) { + } catch (RuntimeException e) { e.printStackTrace(); error = true; } @@ -369,7 +370,7 @@ public class SSLEepGet extends EepGet { System.out.println(" Valid To: " + cert.getNotAfter()); try { cert.checkValidity(); - } catch (Exception e) { + } catch (GeneralSecurityException e) { System.out.println(" WARNING: Certificate is not currently valid, it cannot be used"); } CertUtil.saveCert(cert, new File(name)); @@ -553,11 +554,11 @@ public class SSLEepGet extends EepGet { String req = getRequest(); - //try { - URL url = new URL(_actualURL); - String host = null; - int port = 0; - if ("https".equals(url.getProtocol())) { + String host; + int port; + try { + URI url = new URI(_actualURL); + if ("https".equals(url.getScheme())) { host = url.getHost(); if (host.toLowerCase(Locale.US).endsWith(".i2p")) throw new MalformedURLException("I2P addresses unsupported"); @@ -589,10 +590,11 @@ public class SSLEepGet extends EepGet { } else { throw new MalformedURLException("Only https supported: " + _actualURL); } - // an MUE is an IOE - //} catch (MalformedURLException mue) { - // throw new IOException("Request URL is invalid"); - //} + } catch (URISyntaxException use) { + IOException ioe = new MalformedURLException("Redirected to invalid URL"); + ioe.initCause(use); + throw ioe; + } _proxyIn = _proxy.getInputStream(); _proxyOut = _proxy.getOutputStream(); diff --git a/core/java/src/net/i2p/util/ShellCommand.java b/core/java/src/net/i2p/util/ShellCommand.java index 955830fe1..4a5daac55 100644 --- a/core/java/src/net/i2p/util/ShellCommand.java +++ b/core/java/src/net/i2p/util/ShellCommand.java @@ -439,7 +439,7 @@ public class ShellCommand { System.out.println("ShellCommand waiting for \"" + name + '\"'); try { process.waitFor(); - } catch (Exception e) { + } catch (InterruptedException e) { if (DEBUG) { System.out.println("ShellCommand exception waiting for \"" + name + '\"'); e.printStackTrace(); @@ -457,7 +457,7 @@ public class ShellCommand { if (process.exitValue() > 0) return false; } - } catch (Exception e) { + } catch (IOException e) { // probably IOException, file not found from exec() if (DEBUG) { System.out.println("ShellCommand execute exception for \"" + name + '\"'); diff --git a/core/java/src/net/metanotion/io/block/BlockFile.java b/core/java/src/net/metanotion/io/block/BlockFile.java index 018702204..122f30796 100644 --- a/core/java/src/net/metanotion/io/block/BlockFile.java +++ b/core/java/src/net/metanotion/io/block/BlockFile.java @@ -147,7 +147,7 @@ public class BlockFile implements Closeable { bf.bfck(true); bf.close(); raif.close(); - } catch (Exception e) { + } catch (IOException e) { e.printStackTrace(); } } diff --git a/installer/java/src/net/i2p/installer/Exec.java b/installer/java/src/net/i2p/installer/Exec.java index b8488ceff..de7419202 100644 --- a/installer/java/src/net/i2p/installer/Exec.java +++ b/installer/java/src/net/i2p/installer/Exec.java @@ -1,6 +1,7 @@ package net.i2p.installer; import java.io.File; +import java.io.IOException; /** *

    This class can be used by the installer to execute shell commands.

    @@ -20,8 +21,9 @@ public class Exec { // http://cephas.net/blog/2004/03/23/external_applications_javas_runtimeexec.html try { proc.exitValue(); } catch (Throwable t) { } Runtime.getRuntime().halt(0); - - } catch (Exception e) { + } catch (IOException e) { + e.printStackTrace(); + } catch (RuntimeException e) { e.printStackTrace(); } } diff --git a/installer/tools/java/src/net/i2p/router/networkdb/kademlia/BundleRouterInfos.java b/installer/tools/java/src/net/i2p/router/networkdb/kademlia/BundleRouterInfos.java index f916e976f..cab5991d3 100644 --- a/installer/tools/java/src/net/i2p/router/networkdb/kademlia/BundleRouterInfos.java +++ b/installer/tools/java/src/net/i2p/router/networkdb/kademlia/BundleRouterInfos.java @@ -24,6 +24,7 @@ import java.util.Properties; import gnu.getopt.Getopt; import net.i2p.I2PAppContext; +import net.i2p.data.DataFormatException; import net.i2p.data.Hash; import net.i2p.data.router.RouterAddress; import net.i2p.data.router.RouterInfo; @@ -109,7 +110,9 @@ public class BundleRouterInfos { RouterInfo ri = new RouterInfo(); ri.readBytes(fis, true); // true = verify sig on read me = ri.getIdentity().getHash(); - } catch (Exception e) { + } catch (IOException e) { + //System.out.println("Can't determine our identity"); + } catch (DataFormatException e) { //System.out.println("Can't determine our identity"); } finally { if (fis != null) try { fis.close(); } catch (IOException ioe) {} @@ -209,7 +212,9 @@ public class BundleRouterInfos { copied++; else System.out.println("Failed copy of " + file + " to " + toDir); - } catch (Exception e) { + } catch (IOException e) { + System.out.println("Skipping bad " + file); + } catch (DataFormatException e) { System.out.println("Skipping bad " + file); } finally { if (fis != null) try { fis.close(); } catch (IOException ioe) {} diff --git a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java index 4a5c94638..1df280349 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java @@ -68,7 +68,7 @@ public class DatabaseSearchReplyMessage extends FastI2NPMessageImpl { curIndex += Hash.HASH_LENGTH; //_key = new Hash(keyData); - int num = (int)DataHelper.fromLong(data, curIndex, 1); + int num = data[curIndex] & 0xff; curIndex++; _peerHashes.clear(); diff --git a/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java b/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java index 9669d6f91..5f5941512 100644 --- a/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java +++ b/router/java/src/net/i2p/data/i2np/DeliveryInstructions.java @@ -209,7 +209,7 @@ public class DeliveryInstructions extends DataStructureImpl { public int readBytes(byte data[], int offset) throws DataFormatException { int cur = offset; - long flags = DataHelper.fromLong(data, cur, 1); + int flags = data[cur] & 0xff; cur++; //if (_log.shouldLog(Log.DEBUG)) // _log.debug("Read flags: " + flags + " mode: " + flagMode(flags)); diff --git a/router/java/src/net/i2p/data/i2np/FastI2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/FastI2NPMessageImpl.java index 564d0f726..912a9e2b9 100644 --- a/router/java/src/net/i2p/data/i2np/FastI2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/FastI2NPMessageImpl.java @@ -85,7 +85,7 @@ public abstract class FastI2NPMessageImpl extends I2NPMessageImpl { throw new I2NPMessageException("Payload is too short " + maxLen); int cur = offset; if (type < 0) { - type = (int)DataHelper.fromLong(data, cur, 1); + type = data[cur] & 0xff; cur++; } _uniqueId = DataHelper.fromLong(data, cur, 4); diff --git a/router/java/src/net/i2p/data/i2np/GarlicClove.java b/router/java/src/net/i2p/data/i2np/GarlicClove.java index 628874d81..d19435321 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicClove.java +++ b/router/java/src/net/i2p/data/i2np/GarlicClove.java @@ -158,7 +158,7 @@ public class GarlicClove extends DataStructureImpl { if (m.length <= 0) throw new RuntimeException("foo, returned 0 length"); out.write(m); - } catch (Exception e) { + } catch (RuntimeException e) { throw new DataFormatException("Unable to write the clove: " + _msg + " to " + out, e); } DataHelper.writeLong(out, 4, _cloveId); @@ -187,7 +187,7 @@ public class GarlicClove extends DataStructureImpl { byte m[] = _msg.toByteArray(); System.arraycopy(m, 0, rv, offset, m.length); offset += m.length; - } catch (Exception e) { throw new RuntimeException("Unable to write: " + _msg + ": " + e.getMessage()); } + } catch (RuntimeException e) { throw new RuntimeException("Unable to write: " + _msg + ": " + e.getMessage()); } DataHelper.toLong(rv, offset, 4, _cloveId); offset += 4; DataHelper.toDate(rv, offset, _expiration.getTime()); diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java index fe1225f74..224918ef4 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java @@ -59,7 +59,7 @@ public class I2NPMessageHandler { _lastSize = msg.readBytes(in, type, _messageBuffer); } catch (I2NPMessageException ime) { throw ime; - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.WARN)) _log.warn("Error reading the stream", e); throw new I2NPMessageException("Unknown error reading the " + msg.getClass().getSimpleName(), e); @@ -109,7 +109,7 @@ public class I2NPMessageHandler { public int readMessage(byte data[], int offset, int maxLen) throws I2NPMessageException { int cur = offset; // we will assume that maxLen is >= 1 here. It's checked to be >= 16 in readBytes() - int type = (int)DataHelper.fromLong(data, cur, 1); + int type = data[cur] & 0xff; cur++; _lastReadBegin = System.currentTimeMillis(); I2NPMessage msg = I2NPMessageImpl.createMessage(_context, type); @@ -131,7 +131,7 @@ public class I2NPMessageHandler { cur += _lastSize; } catch (I2NPMessageException ime) { throw ime; - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.WARN)) _log.warn("Error reading the stream", e); throw new I2NPMessageException("Unknown error reading the " + msg.getClass().getSimpleName(), e); diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 5f14c3fef..062e310b1 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -197,7 +197,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM throw new I2NPMessageException("Payload is too short " + maxLen); int cur = offset; if (type < 0) { - type = (int)DataHelper.fromLong(data, cur, 1); + type = data[cur] & 0xff; cur++; } _uniqueId = DataHelper.fromLong(data, cur, 4); @@ -413,7 +413,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM */ public static I2NPMessage fromRawByteArray(I2PAppContext ctx, byte buffer[], int offset, int len, I2NPMessageHandler handler) throws I2NPMessageException { - int type = (int)DataHelper.fromLong(buffer, offset, 1); + int type = buffer[offset] & 0xff; offset++; I2NPMessage msg = createMessage(ctx, type); if (msg == null) diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java b/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java index f253cfed2..d23a489d6 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java @@ -163,7 +163,7 @@ public class I2NPMessageReader { _log.warn("IO Error handling message", ioe); _listener.disconnected(I2NPMessageReader.this); cancelRunner(); - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "error reading msg!", e); _listener.readError(I2NPMessageReader.this, e); _listener.disconnected(I2NPMessageReader.this); diff --git a/router/java/src/net/i2p/data/i2np/VariableTunnelBuildMessage.java b/router/java/src/net/i2p/data/i2np/VariableTunnelBuildMessage.java index b33cba761..52aa565de 100644 --- a/router/java/src/net/i2p/data/i2np/VariableTunnelBuildMessage.java +++ b/router/java/src/net/i2p/data/i2np/VariableTunnelBuildMessage.java @@ -29,7 +29,7 @@ public class VariableTunnelBuildMessage extends TunnelBuildMessage { @Override public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException { // message type will be checked in super() - int r = (int)DataHelper.fromLong(data, offset, 1); + int r = data[offset] & 0xff; if (r <= 0 || r > MAX_RECORD_COUNT) throw new I2NPMessageException("Bad record count " + r); RECORD_COUNT = r; diff --git a/router/java/src/net/i2p/data/i2np/VariableTunnelBuildReplyMessage.java b/router/java/src/net/i2p/data/i2np/VariableTunnelBuildReplyMessage.java index 368104a2a..575f55630 100644 --- a/router/java/src/net/i2p/data/i2np/VariableTunnelBuildReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/VariableTunnelBuildReplyMessage.java @@ -31,7 +31,7 @@ public class VariableTunnelBuildReplyMessage extends TunnelBuildReplyMessage { @Override public void readMessage(byte[] data, int offset, int dataSize, int type) throws I2NPMessageException { // message type will be checked in super() - int r = (int)DataHelper.fromLong(data, offset, 1); + int r = data[offset] & 0xff; if (r <= 0 || r > MAX_RECORD_COUNT) throw new I2NPMessageException("Bad record count " + r); RECORD_COUNT = r; diff --git a/router/java/src/net/i2p/data/router/RouterInfo.java b/router/java/src/net/i2p/data/router/RouterInfo.java index 0d60c6dc0..f2f9cdb7f 100644 --- a/router/java/src/net/i2p/data/router/RouterInfo.java +++ b/router/java/src/net/i2p/data/router/RouterInfo.java @@ -724,7 +724,10 @@ public class RouterInfo extends DatabaseEntry { System.err.println("Router info " + args[i] + " is invalid"); fail = true; } - } catch (Exception e) { + } catch (IOException e) { + System.err.println("Error reading " + args[i] + ": " + e); + fail = true; + } catch (DataFormatException e) { System.err.println("Error reading " + args[i] + ": " + e); fail = true; } finally { diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java index fb4c2a632..bfd3d696e 100644 --- a/router/java/src/net/i2p/router/InNetMessagePool.java +++ b/router/java/src/net/i2p/router/InNetMessagePool.java @@ -434,7 +434,7 @@ public class InNetMessagePool implements Service { } catch (OutOfMemoryError oome) { throw oome; - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.CRIT)) _log.log(Log.CRIT, "Error in the tunnel gateway dispatcher", e); } @@ -467,7 +467,7 @@ public class InNetMessagePool implements Service { } catch (OutOfMemoryError oome) { throw oome; - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.CRIT)) _log.log(Log.CRIT, "Error in the tunnel data dispatcher", e); } diff --git a/router/java/src/net/i2p/router/JobTiming.java b/router/java/src/net/i2p/router/JobTiming.java index f934f1556..c9c0efb03 100644 --- a/router/java/src/net/i2p/router/JobTiming.java +++ b/router/java/src/net/i2p/router/JobTiming.java @@ -16,7 +16,7 @@ import net.i2p.util.Clock; * * For use by the router only. Not to be used by applications or plugins. */ -public class JobTiming implements Clock.ClockUpdateListener, RouterClock.ClockShiftListener { +public class JobTiming implements Clock.ClockUpdateListener { private volatile long _start; private volatile long _actualStart; private volatile long _actualEnd; @@ -82,8 +82,4 @@ public class JobTiming implements Clock.ClockUpdateListener, RouterClock.ClockSh if (_actualEnd != 0) _actualEnd += delta; } - - public void clockShift(long delta) { - offsetChanged(delta); - } } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 426da4a75..99073c366 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -9,6 +9,7 @@ package net.i2p.router; */ import java.io.File; +import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -648,7 +649,7 @@ public class Router implements RouterClock.ClockShiftListener { //else // System.err.println("WARNING: Configuration file " + filename + " does not exist"); } - } catch (Exception ioe) { + } catch (IOException ioe) { if (log != null) log.error("Error loading the router configuration from " + filename, ioe); else @@ -1351,7 +1352,7 @@ public class Router implements RouterClock.ClockShiftListener { ordered.putAll(_config); DataHelper.storeProps(ordered, new File(_configFilename)); } - } catch (Exception ioe) { + } catch (IOException ioe) { // warning, _log will be null when called from constructor if (_log != null) _log.error("Error saving the config to " + _configFilename, ioe); diff --git a/router/java/src/net/i2p/router/dummy/VMCommSystem.java b/router/java/src/net/i2p/router/dummy/VMCommSystem.java index 13b8aff0a..29f232370 100644 --- a/router/java/src/net/i2p/router/dummy/VMCommSystem.java +++ b/router/java/src/net/i2p/router/dummy/VMCommSystem.java @@ -8,6 +8,7 @@ import java.util.Map; import net.i2p.data.Hash; import net.i2p.data.i2np.I2NPMessage; +import net.i2p.data.i2np.I2NPMessageException; import net.i2p.data.i2np.I2NPMessageHandler; import net.i2p.router.CommSystemFacade; import net.i2p.router.JobImpl; @@ -121,7 +122,7 @@ public class VMCommSystem extends CommSystemFacade { ReceiveJob.this.getContext().statManager().addRateData("transport.receiveMessageLarge", 1, 1); _ctx.inNetMessagePool().add(msg, null, _from); - } catch (Exception e) { + } catch (I2NPMessageException e) { _log.error("Error reading/formatting a VM message? Something is not right...", e); } } diff --git a/router/java/src/net/i2p/router/message/GarlicMessageParser.java b/router/java/src/net/i2p/router/message/GarlicMessageParser.java index df83702a2..ef0e5f0b7 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageParser.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageParser.java @@ -75,7 +75,7 @@ public class GarlicMessageParser { private CloveSet readCloveSet(byte data[]) throws DataFormatException { int offset = 0; - int numCloves = (int)DataHelper.fromLong(data, offset, 1); + int numCloves = data[offset] & 0xff; offset++; if (_log.shouldLog(Log.DEBUG)) _log.debug("# cloves to read: " + numCloves); diff --git a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java index 8a517a806..fd45bc752 100644 --- a/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java +++ b/router/java/src/net/i2p/router/message/OutboundClientMessageOneShotJob.java @@ -949,15 +949,19 @@ public class OutboundClientMessageOneShotJob extends JobImpl { if (_outTunnel.getLength() > 0) size = ((size + 1023) / 1024) * 1024; // messages are in ~1KB blocks - for (int i = 0; i < _outTunnel.getLength(); i++) { + // skip ourselves at first hop + for (int i = 1; i < _outTunnel.getLength(); i++) { getContext().profileManager().tunnelTestSucceeded(_outTunnel.getPeer(i), sendTime); getContext().profileManager().tunnelDataPushed(_outTunnel.getPeer(i), sendTime, size); } _outTunnel.incrementVerifiedBytesTransferred(size); } - if (_inTunnel != null) - for (int i = 0; i < _inTunnel.getLength(); i++) + if (_inTunnel != null) { + // skip ourselves at last hop + for (int i = 0; i < _inTunnel.getLength() - 1; i++) { getContext().profileManager().tunnelTestSucceeded(_inTunnel.getPeer(i), sendTime); + } + } } public void setMessage(I2NPMessage msg) {} diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java index a04a339cc..f915b03f7 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/PersistentDataStore.java @@ -543,7 +543,7 @@ public class PersistentDataStore extends TransientDataStore { if (_log.shouldLog(Log.INFO)) _log.info("Unable to read the router reference in " + _routerFile.getName(), ioe); corrupt = true; - } catch (Exception e) { + } catch (RuntimeException e) { // key certificate problems, etc., don't let one bad RI kill the whole thing if (_log.shouldLog(Log.INFO)) _log.info("Unable to read the router reference in " + _routerFile.getName(), e); @@ -666,7 +666,7 @@ public class PersistentDataStore extends TransientDataStore { return null; Hash h = Hash.create(b); return h; - } catch (Exception e) { + } catch (RuntimeException e) { // static //_log.warn("Unable to fetch the key from [" + filename + "]", e); return null; diff --git a/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java b/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java index d6fc00f4e..25cd334ac 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/ReseedChecker.java @@ -3,7 +3,7 @@ package net.i2p.router.networkdb.reseed; import java.io.File; import java.io.InputStream; import java.io.IOException; -import java.net.URL; +import java.net.URI; import java.util.concurrent.atomic.AtomicBoolean; import net.i2p.data.DataHelper; @@ -131,7 +131,7 @@ public class ReseedChecker { * @throws IllegalArgumentException if it doesn't end with zip or su3 * @since 0.9.19 */ - public boolean requestReseed(URL url) throws IllegalArgumentException { + public boolean requestReseed(URI url) throws IllegalArgumentException { if (_inProgress.compareAndSet(false, true)) { Reseeder reseeder = new Reseeder(_context, this); try { diff --git a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java index fa8d4c2d2..e908db35f 100644 --- a/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java +++ b/router/java/src/net/i2p/router/networkdb/reseed/Reseeder.java @@ -7,10 +7,8 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.util.Arrays; import java.util.ArrayList; import java.util.Collections; @@ -152,7 +150,7 @@ public class Reseeder { * @throws IllegalArgumentException if it doesn't end with zip or su3 * @since 0.9.19 */ - void requestReseed(URL url) throws IllegalArgumentException { + void requestReseed(URI url) throws IllegalArgumentException { ReseedRunner reseedRunner = new ReseedRunner(url); // set to daemon so it doesn't hang a shutdown Thread reseed = new I2PAppThread(reseedRunner, "Reseed", true); @@ -238,7 +236,7 @@ public class Reseeder { /** bytes per sec for each su3 downloaded */ private final List _bandwidths; private static final int MAX_DATE_SETS = 2; - private final URL _url; + private final URI _url; /** * Start a reseed from the default URL list @@ -255,7 +253,7 @@ public class Reseeder { * @throws IllegalArgumentException if it doesn't end with zip or su3 * @since 0.9.19 */ - public ReseedRunner(URL url) throws IllegalArgumentException { + public ReseedRunner(URI url) throws IllegalArgumentException { String lc = url.getPath().toLowerCase(Locale.US); if (!(lc.endsWith(".zip") || lc.endsWith(".su3"))) throw new IllegalArgumentException("Reseed URL must end with .zip or .su3"); @@ -411,7 +409,7 @@ public class Reseeder { * @return count of routerinfos successfully fetched, or -1 if no valid URLs */ private int reseed(boolean echoStatus) { - List URLList = new ArrayList(); + List URLList = new ArrayList(); String URLs = _context.getProperty(PROP_RESEED_URL); boolean defaulted = URLs == null; boolean SSLDisable = _context.getBooleanProperty(PROP_SSL_DISABLE); @@ -428,29 +426,29 @@ public class Reseeder { if (!u.endsWith("/")) u = u + '/'; try { - URLList.add(new URL(u)); - } catch (MalformedURLException mue) {} + URLList.add(new URI(u)); + } catch (URISyntaxException mue) {} } Collections.shuffle(URLList, _context.random()); if (!SSLDisable && !SSLRequired) { // put the non-SSL at the end of the SSL - List URLList2 = new ArrayList(); + List URLList2 = new ArrayList(); tok = new StringTokenizer(DEFAULT_SEED_URL, " ,"); while (tok.hasMoreTokens()) { String u = tok.nextToken().trim(); if (!u.endsWith("/")) u = u + '/'; try { - URLList2.add(new URL(u)); - } catch (MalformedURLException mue) {} + URLList2.add(new URI(u)); + } catch (URISyntaxException mue) {} } Collections.shuffle(URLList2, _context.random()); URLList.addAll(URLList2); } } else { // custom list given - List SSLList = new ArrayList(); - List nonSSLList = new ArrayList(); + List SSLList = new ArrayList(); + List nonSSLList = new ArrayList(); StringTokenizer tok = new StringTokenizer(URLs, " ,"); while (tok.hasMoreTokens()) { // format tokens @@ -460,12 +458,12 @@ public class Reseeder { // check if ssl or not then add to respective list if (u.startsWith("https")) { try { - SSLList.add(new URL(u)); - } catch (MalformedURLException mue) {} + SSLList.add(new URI(u)); + } catch (URISyntaxException mue) {} } else { try { - nonSSLList.add(new URL(u)); - } catch (MalformedURLException mue) {} + nonSSLList.add(new URI(u)); + } catch (URISyntaxException mue) {} } } // shuffle lists @@ -481,8 +479,8 @@ public class Reseeder { } if (!isSNISupported()) { try { - URLList.remove(new URL("https://netdb.i2p2.no/")); - } catch (MalformedURLException mue) {} + URLList.remove(new URI("https://netdb.i2p2.no/")); + } catch (URISyntaxException mue) {} } if (URLList.isEmpty()) { System.out.println("No valid reseed URLs"); @@ -500,19 +498,19 @@ public class Reseeder { * @param echoStatus apparently always false * @return count of routerinfos successfully fetched */ - private int reseed(List URLList, boolean echoStatus) { + private int reseed(List URLList, boolean echoStatus) { int total = 0; for (int i = 0; i < URLList.size() && _isRunning; i++) { if (_context.router().gracefulShutdownInProgress()) { System.out.println("Reseed aborted, shutdown in progress"); return total; } - URL url = URLList.get(i); + URI url = URLList.get(i); int dl = 0; if (ENABLE_SU3) { try { - dl = reseedSU3(new URL(url.toString() + SU3_FILENAME), echoStatus); - } catch (MalformedURLException mue) {} + dl = reseedSU3(new URI(url.toString() + SU3_FILENAME), echoStatus); + } catch (URISyntaxException mue) {} } if (ENABLE_NON_SU3) { if (dl <= 0) @@ -556,7 +554,7 @@ public class Reseeder { * @param echoStatus apparently always false * @return count of routerinfos successfully fetched **/ - private int reseedOne(URL seedURL, boolean echoStatus) { + private int reseedOne(URI seedURL, boolean echoStatus) { try { // Don't use context clock as we may be adjusting the time final long timeLimit = System.currentTimeMillis() + MAX_TIME_PER_HOST; @@ -627,7 +625,7 @@ public class Reseeder { if (fetched % 60 == 0) System.out.println(); } - } catch (Exception e) { + } catch (RuntimeException e) { if (_log.shouldLog(Log.INFO)) _log.info("Failed fetch", e); errors++; @@ -658,7 +656,7 @@ public class Reseeder { * @return count of routerinfos successfully fetched * @since 0.9.14 **/ - public int reseedSU3(URL seedURL, boolean echoStatus) { + public int reseedSU3(URI seedURL, boolean echoStatus) { return reseedSU3OrZip(seedURL, true, echoStatus); } @@ -672,7 +670,7 @@ public class Reseeder { * @return count of routerinfos successfully fetched * @since 0.9.19 **/ - public int reseedZip(URL seedURL, boolean echoStatus) { + public int reseedZip(URI seedURL, boolean echoStatus) { return reseedSU3OrZip(seedURL, false, echoStatus); } @@ -686,7 +684,7 @@ public class Reseeder { * @return count of routerinfos successfully fetched * @since 0.9.19 **/ - private int reseedSU3OrZip(URL seedURL, boolean isSU3, boolean echoStatus) { + private int reseedSU3OrZip(URI seedURL, boolean isSU3, boolean echoStatus) { int fetched = 0; int errors = 0; File contentRaw = null; @@ -868,7 +866,7 @@ public class Reseeder { if (ourHash != null && DataHelper.eq(hash, ourHash.getData())) return false; - URL url = new URL(seedURL + (seedURL.endsWith("/") ? "" : "/") + ROUTERINFO_PREFIX + peer + ROUTERINFO_SUFFIX); + URI url = new URI(seedURL + (seedURL.endsWith("/") ? "" : "/") + ROUTERINFO_PREFIX + peer + ROUTERINFO_SUFFIX); byte data[] = readURL(url); if (data == null || data.length <= 0) @@ -877,7 +875,7 @@ public class Reseeder { } /** @return null on error */ - private byte[] readURL(URL url) throws IOException { + private byte[] readURL(URI url) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024); EepGet get; boolean ssl = url.toString().startsWith("https"); @@ -922,7 +920,7 @@ public class Reseeder { * @return null on error * @since 0.9.14 */ - private File fetchURL(URL url) throws IOException { + private File fetchURL(URI url) throws IOException { File out = new File(_context.getTempDir(), "reseed-" + _context.random().nextInt() + ".tmp"); EepGet get; boolean ssl = url.toString().startsWith("https"); diff --git a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java index 87f751bdc..ea800858b 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java +++ b/router/java/src/net/i2p/router/peermanager/ProfileOrganizer.java @@ -156,6 +156,11 @@ public class ProfileOrganizer { * Blocking if a reorganize is happening. */ public PeerProfile getProfile(Hash peer) { + if (peer.equals(_us)) { + if (_log.shouldWarn()) + _log.warn("Who wanted our own profile?", new Exception("I did")); + return null; + } getReadLock(); try { return locked_getProfile(peer); @@ -168,6 +173,11 @@ public class ProfileOrganizer { * @since 0.8.12 */ public PeerProfile getProfileNonblocking(Hash peer) { + if (peer.equals(_us)) { + if (_log.shouldWarn()) + _log.warn("Who wanted our own profile?", new Exception("I did")); + return null; + } if (tryReadLock()) { try { return locked_getProfile(peer); @@ -184,6 +194,11 @@ public class ProfileOrganizer { if (profile == null) return null; Hash peer = profile.getPeer(); + if (peer.equals(_us)) { + if (_log.shouldWarn()) + _log.warn("Who added our own profile?", new Exception("I did")); + return null; + } if (_log.shouldLog(Log.DEBUG)) _log.debug("New profile created for " + peer); diff --git a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java index 305d0f343..af9cd33aa 100644 --- a/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java +++ b/router/java/src/net/i2p/router/peermanager/ProfilePersistenceHelper.java @@ -301,7 +301,7 @@ class ProfilePersistenceHelper { _log.debug("Loaded the profile for " + peer.toBase64() + " from " + file.getName()); return profile; - } catch (Exception e) { + } catch (IOException e) { if (_log.shouldLog(Log.WARN)) _log.warn("Error loading properties from " + file.getAbsolutePath(), e); file.delete(); @@ -369,7 +369,7 @@ class ProfilePersistenceHelper { return null; Hash h = Hash.create(b); return h; - } catch (Exception dfe) { + } catch (RuntimeException dfe) { _log.warn("Invalid base64 [" + key + "]", dfe); return null; } diff --git a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java index ef0826cf5..a3302ae40 100644 --- a/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java +++ b/router/java/src/net/i2p/router/startup/RebuildRouterInfoJob.java @@ -98,7 +98,13 @@ class RebuildRouterInfoJob extends JobImpl { KeyData kd = LoadRouterInfoJob.readKeyData(keyFile, keyFile2); info = new RouterInfo(); info.setIdentity(kd.routerIdentity); - } catch (Exception e) { + } catch (DataFormatException e) { + _log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e); + keyFile.delete(); + keyFile2.delete(); + rebuildRouterInfo(alreadyRunning); + return; + } catch (IOException e) { _log.log(Log.CRIT, "Error reading in the key data from " + keyFile.getAbsolutePath(), e); keyFile.delete(); keyFile2.delete(); diff --git a/router/java/src/net/i2p/router/startup/WorkingDir.java b/router/java/src/net/i2p/router/startup/WorkingDir.java index 8e3a19c93..a7ca9f330 100644 --- a/router/java/src/net/i2p/router/startup/WorkingDir.java +++ b/router/java/src/net/i2p/router/startup/WorkingDir.java @@ -211,7 +211,7 @@ public class WorkingDir { String[] files = dir.list(); if (files == null) return false; - String migrated[] = MIGRATE_BASE.split(","); + String migrated[] = DataHelper.split(MIGRATE_BASE, ","); for (String file: files) { for (int i = 0; i < migrated.length; i++) { if (file.equals(migrated[i])) @@ -282,7 +282,7 @@ public class WorkingDir { private static boolean migrate(String list, File olddir, File todir) { boolean rv = true; - String files[] = list.split(","); + String files[] = DataHelper.split(list, ","); for (int i = 0; i < files.length; i++) { File from = new File(olddir, files[i]); if (!copy(from, todir)) { diff --git a/router/java/src/net/i2p/router/time/Zones.java b/router/java/src/net/i2p/router/time/Zones.java index 85d5e388e..d04c67408 100644 --- a/router/java/src/net/i2p/router/time/Zones.java +++ b/router/java/src/net/i2p/router/time/Zones.java @@ -10,6 +10,7 @@ import java.util.Locale; import java.util.Map; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; import net.i2p.router.transport.GeoIP; /** @@ -105,7 +106,7 @@ class Zones { try { if (line.charAt(0) == '#') continue; - String[] s = line.split(","); + String[] s = DataHelper.split(line, ","); String ucContinent = s[1].toUpperCase(Locale.US).trim(); String zone = _continentToZone.get(ucContinent); if (zone == null) diff --git a/router/java/src/net/i2p/router/transport/GeoIP.java b/router/java/src/net/i2p/router/transport/GeoIP.java index 3213be64e..6a2040164 100644 --- a/router/java/src/net/i2p/router/transport/GeoIP.java +++ b/router/java/src/net/i2p/router/transport/GeoIP.java @@ -17,6 +17,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.router.Router; import net.i2p.router.RouterContext; @@ -209,7 +210,7 @@ public class GeoIP { if (line.charAt(0) == '#') { continue; } - String[] s = line.split(","); + String[] s = DataHelper.split(line, ","); String lc = s[0].toLowerCase(Locale.US); _codeToName.put(lc, s[1]); _codeCache.put(lc, lc); @@ -274,7 +275,7 @@ public class GeoIP { if (buf.charAt(0) == '#') { continue; } - String[] s = buf.split(","); + String[] s = DataHelper.split(buf, ","); long ip1 = Long.parseLong(s[0]); long ip2 = Long.parseLong(s[1]); while (idx < search.length && search[idx].longValue() < ip1) { diff --git a/router/java/src/net/i2p/router/transport/GeoIPv6.java b/router/java/src/net/i2p/router/transport/GeoIPv6.java index b93e3f004..af3120480 100644 --- a/router/java/src/net/i2p/router/transport/GeoIPv6.java +++ b/router/java/src/net/i2p/router/transport/GeoIPv6.java @@ -170,7 +170,7 @@ class GeoIPv6 { if (buf.charAt(0) == '#') { continue; } - String[] s = buf.split(","); + String[] s = DataHelper.split(buf, ","); String ips1 = s[0].replace("\"", "").trim(); String ips2 = s[1].replace("\"", "").trim(); byte[] ip1 = InetAddress.getByName(ips1).getAddress(); diff --git a/router/java/src/net/i2p/router/transport/UPnP.java b/router/java/src/net/i2p/router/transport/UPnP.java index 26c7610b5..58cc32c75 100644 --- a/router/java/src/net/i2p/router/transport/UPnP.java +++ b/router/java/src/net/i2p/router/transport/UPnP.java @@ -4,9 +4,9 @@ package net.i2p.router.transport; import java.net.InetAddress; -import java.net.MalformedURLException; import java.net.UnknownHostException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -224,7 +224,7 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { boolean ignore = false; String toIgnore = _context.getProperty(PROP_IGNORE); if (toIgnore != null) { - String[] ignores = toIgnore.split("[,; \r\n\t]"); + String[] ignores = DataHelper.split(toIgnore, "[,; \r\n\t]"); for (int i = 0; i < ignores.length; i++) { if (ignores[i].equals(udn)) { ignore = true; @@ -476,7 +476,7 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { ServiceStateTable table; try { table = serv.getServiceStateTable(); - } catch (Exception e) { + } catch (RuntimeException e) { // getSCPDNode() returns null, // NPE at org.cybergarage.upnp.Service.getServiceStateTable(Service.java:526) sb.append(" : no state"); @@ -823,17 +823,17 @@ class UPnP extends ControlPoint implements DeviceChangeListener, EventListener { String him = _router.getURLBase(); if (him != null && him.length() > 0) { try { - URL url = new URL(him); + URI url = new URI(him); hisIP = url.getHost(); - } catch (MalformedURLException mue) {} + } catch (URISyntaxException use) {} } if (hisIP == null) { him = _router.getLocation(); if (him != null && him.length() > 0) { try { - URL url = new URL(him); + URI url = new URI(him); hisIP = url.getHost(); - } catch (MalformedURLException mue) {} + } catch (URISyntaxException use) {} } } if (hisIP == null) diff --git a/router/java/src/net/i2p/router/transport/UPnPManager.java b/router/java/src/net/i2p/router/transport/UPnPManager.java index 9d7a6918a..cd9963b06 100644 --- a/router/java/src/net/i2p/router/transport/UPnPManager.java +++ b/router/java/src/net/i2p/router/transport/UPnPManager.java @@ -88,7 +88,7 @@ class UPnPManager { _isRunning = _upnp.runPlugin(); if (_log.shouldLog(Log.INFO)) _log.info("UPnP runPlugin took " + (_context.clock().now() - b)); - } catch (Exception e) { + } catch (RuntimeException e) { // NPE in UPnP (ticket #728), can't let it bring us down if (!_errorLogged) { _log.error("UPnP error, please report", e); diff --git a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java index 053d4a373..dcc2226c4 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EventPumper.java @@ -335,7 +335,7 @@ class EventPumper implements Runnable { con.close(); key.cancel(); } - } catch (Exception ke) { + } catch (IOException ke) { _log.error("Error closing key " + key + " on pumper shutdown", ke); } } @@ -344,7 +344,7 @@ class EventPumper implements Runnable { if (_log.shouldLog(Log.DEBUG)) _log.debug("Closing down the event pumper with no selection keys remaining"); } - } catch (Exception e) { + } catch (IOException e) { _log.error("Error closing keys on pumper shutdown", e); } _wantsConRegister.clear(); diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java index 703ee5050..37504a111 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java @@ -463,7 +463,7 @@ class NTCPConnection implements Closeable { _transport.afterSend(msg, successful, allowRequeue, msg.getLifetime()); if (_consecutiveBacklog > 10) { // waaay too backlogged boolean wantsWrite = false; - try { wantsWrite = ( (_conKey.interestOps() & SelectionKey.OP_WRITE) != 0); } catch (Exception e) {} + try { wantsWrite = ( (_conKey.interestOps() & SelectionKey.OP_WRITE) != 0); } catch (RuntimeException e) {} if (_log.shouldLog(Log.WARN)) { int blocks = _writeBufs.size(); _log.warn("Too backlogged for too long (" + _consecutiveBacklog + " messages for " + DataHelper.formatDuration(queueTime()) + ", sched? " + wantsWrite + ", blocks: " + blocks + ") sending to " + _remotePeer.calculateHash()); @@ -521,7 +521,7 @@ class NTCPConnection implements Closeable { + ", wantsWrite? " + (0 != (_conKey.interestOps()&SelectionKey.OP_WRITE)) + ", currentOut set? " + currentOutboundSet + ", writeBufs: " + writeBufs + " on " + toString()); - } catch (Exception e) {} // java.nio.channels.CancelledKeyException + } catch (RuntimeException e) {} // java.nio.channels.CancelledKeyException } //_context.statManager().addRateData("ntcp.sendBacklogTime", queueTime); return true; diff --git a/router/java/src/net/i2p/router/transport/udp/ACKSender.java b/router/java/src/net/i2p/router/transport/udp/ACKSender.java index 8e608ab13..60976d285 100644 --- a/router/java/src/net/i2p/router/transport/udp/ACKSender.java +++ b/router/java/src/net/i2p/router/transport/udp/ACKSender.java @@ -148,7 +148,7 @@ class ACKSender implements Runnable { try { // bulk operations may throw an exception _peersToACK.addAll(notYet); - } catch (Exception e) {} + } catch (RuntimeException e) {} if (_log.shouldLog(Log.DEBUG)) _log.debug("sleeping, pending size = " + notYet.size()); notYet.clear(); diff --git a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java index 89076f9ce..77fdd78ba 100644 --- a/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java +++ b/router/java/src/net/i2p/router/transport/udp/EstablishmentManager.java @@ -29,6 +29,7 @@ import net.i2p.router.util.DecayingBloomFilter; import net.i2p.util.Addresses; import net.i2p.util.I2PThread; import net.i2p.util.Log; +import net.i2p.util.VersionComparator; /** * Coordinate the establishment of new sessions - both inbound and outbound. @@ -126,6 +127,19 @@ class EstablishmentManager { /** for the DSM and or netdb store */ private static final int DATA_MESSAGE_TIMEOUT = 10*1000; + /** + * Java I2P has always parsed the length of the extended options field, + * but i2pd hasn't recognized it until this release. + * No matter, the options weren't defined until this release anyway. + * +********************************************************************************************************** + * FIXME 0.9.23 for testing, change to 0.9.24 for release + * + */ + private static final String VERSION_ALLOW_EXTENDED_OPTIONS = "0.9.23"; + private static final String PROP_DISABLE_EXT_OPTS = "i2np.udp.disableExtendedOptions"; + + public EstablishmentManager(RouterContext ctx, UDPTransport transport) { _context = ctx; _log = ctx.logManager().getLog(EstablishmentManager.class); @@ -356,8 +370,16 @@ class EstablishmentManager { _transport.failed(msg, "Peer has bad key, cannot establish"); return; } + boolean allowExtendedOptions = VersionComparator.comp(toRouterInfo.getVersion(), + VERSION_ALLOW_EXTENDED_OPTIONS) >= 0 + && !_context.getBooleanProperty(PROP_DISABLE_EXT_OPTS); + // w/o ext options, it's always 'requested', no need to set + // don't ask if they are indirect + boolean requestIntroduction = allowExtendedOptions && !isIndirect && + _transport.introducersMaybeRequired(); state = new OutboundEstablishState(_context, maybeTo, to, - toIdentity, + toIdentity, allowExtendedOptions, + requestIntroduction, sessionKey, addr, _transport.getDHFactory()); OutboundEstablishState oldState = _outboundStates.putIfAbsent(to, state); boolean isNew = oldState == null; @@ -477,7 +499,9 @@ class EstablishmentManager { // Don't offer to relay to privileged ports. // Only offer for an IPv4 session. // TODO if already we have their RI, only offer if they need it (no 'C' cap) - if (_transport.canIntroduce() && state.getSentPort() >= 1024 && + // if extended options, only if they asked for it + if (state.isIntroductionRequested() && + _transport.canIntroduce() && state.getSentPort() >= 1024 && state.getSentIP().length == 4) { // ensure > 0 long tag = 1 + _context.random().nextLong(MAX_TAG_VALUE); diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java index 590aa29ed..332282c24 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState.java @@ -62,6 +62,8 @@ class InboundEstablishState { private final Queue _queuedMessages; // count for backoff private int _createdSentCount; + // default true + private boolean _introductionRequested = true; public enum InboundState { /** nothin known yet */ @@ -150,6 +152,12 @@ class InboundEstablishState { if (_bobIP == null) _bobIP = new byte[req.readIPSize()]; req.readIP(_bobIP, 0); + byte[] ext = req.readExtendedOptions(); + if (ext != null && ext.length >= UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH) { + _introductionRequested = (ext[1] & (byte) UDPPacket.SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG) != 0; + if (_log.shouldInfo()) + _log.info("got sess req. w/ ext. options, need intro? " + _introductionRequested + ' ' + this); + } if (_log.shouldLog(Log.DEBUG)) _log.debug("Receive sessionRequest, BobIP = " + Addresses.toString(_bobIP)); if (_currentState == InboundState.IB_STATE_UNKNOWN) @@ -160,6 +168,12 @@ class InboundEstablishState { public synchronized boolean sessionRequestReceived() { return _receivedX != null; } public synchronized byte[] getReceivedX() { return _receivedX; } public synchronized byte[] getReceivedOurIP() { return _bobIP; } + /** + * True (default) if no extended options in session request, + * or value of flag bit in the extended options. + * @since 0.9.24 + */ + public synchronized boolean isIntroductionRequested() { return _introductionRequested; } /** * Generates session key and mac key. diff --git a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java index 1b6bb03c0..d2a3b0414 100644 --- a/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java +++ b/router/java/src/net/i2p/router/transport/udp/MessageReceiver.java @@ -243,7 +243,7 @@ class MessageReceiver { } _context.messageHistory().droppedInboundMessage(state.getMessageId(), state.getFrom(), "error: " + ime.toString() + ": " + state.toString()); return null; - } catch (Exception e) { + } catch (RuntimeException e) { // e.g. AIOOBE if (_log.shouldLog(Log.WARN)) _log.warn("Error handling a message: " + state, e); diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java index 63497b5ea..d849bb836 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState.java @@ -56,6 +56,8 @@ class OutboundEstablishState { private RemoteHostId _remoteHostId; private final RemoteHostId _claimedAddress; private final RouterIdentity _remotePeer; + private final boolean _allowExtendedOptions; + private final boolean _needIntroduction; private final SessionKey _introKey; private final Queue _queuedMessages; private OutboundState _currentState; @@ -107,12 +109,17 @@ class OutboundEstablishState { * @param claimedAddress an IP/port based RemoteHostId, or null if unknown * @param remoteHostId non-null, == claimedAddress if direct, or a hash-based one if indirect * @param remotePeer must have supported sig type + * @param allowExtenededOptions are we allowed to send extended options to Bob? + * @param needIntroduction should we ask Bob to be an introducer for us? + ignored unless allowExtendedOptions is true * @param introKey Bob's introduction key, as published in the netdb * @param addr non-null */ public OutboundEstablishState(RouterContext ctx, RemoteHostId claimedAddress, RemoteHostId remoteHostId, - RouterIdentity remotePeer, SessionKey introKey, UDPAddress addr, + RouterIdentity remotePeer, boolean allowExtendedOptions, + boolean needIntroduction, + SessionKey introKey, UDPAddress addr, DHSessionKeyBuilder.Factory dh) { _context = ctx; _log = ctx.logManager().getLog(OutboundEstablishState.class); @@ -125,6 +132,8 @@ class OutboundEstablishState { } _claimedAddress = claimedAddress; _remoteHostId = remoteHostId; + _allowExtendedOptions = allowExtendedOptions; + _needIntroduction = needIntroduction; _remotePeer = remotePeer; _introKey = introKey; _queuedMessages = new LinkedBlockingQueue(); @@ -157,6 +166,19 @@ class OutboundEstablishState { /** @return -1 if unset */ public long getIntroNonce() { return _introductionNonce; } + + /** + * Are we allowed to send extended options to this peer? + * @since 0.9.24 + */ + public boolean isExtendedOptionsAllowed() { return _allowExtendedOptions; } + + /** + * Should we ask this peer to be an introducer for us? + * Ignored unless allowExtendedOptions is true + * @since 0.9.24 + */ + public boolean needIntroduction() { return _needIntroduction; } /** * Queue a message to be sent after the session is established. diff --git a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java index 3029f96c3..0f7e0ac80 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketBuilder.java @@ -57,10 +57,11 @@ to the various messages - a one byte flag and a four byte sending timestamp (*seconds* since the unix epoch). The flag byte contains the following bitfields:

    -  bits 0-3: payload type
    -     bit 4: rekey?
    -     bit 5: extended options included
    -  bits 6-7: reserved
    +Bit order: 76543210
    +  bits 7-4: payload type
    +     bit 3: rekey?
    +     bit 2: extended options included
    +  bits 1-0: reserved
     

    If the rekey flag is set, 64 bytes of keying material follow the @@ -166,6 +167,19 @@ class PacketBuilder { private static final String PROP_PADDING = "i2np.udp.padding"; private static final boolean DEFAULT_ENABLE_PADDING = true; + /** + * The nine message types, 0-8, shifted to bits 7-4 for convenience + */ + private static final byte SESSION_REQUEST_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST << 4; + private static final byte SESSION_CREATED_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_SESSION_CREATED << 4; + private static final byte SESSION_CONFIRMED_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED << 4; + private static final byte PEER_RELAY_REQUEST_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_RELAY_REQUEST << 4; + private static final byte PEER_RELAY_RESPONSE_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_RELAY_RESPONSE << 4; + private static final byte PEER_RELAY_INTRO_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_RELAY_INTRO << 4; + private static final byte DATA_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_DATA << 4; + private static final byte PEER_TEST_FLAG_BYTE = UDPPacket.PAYLOAD_TYPE_TEST << 4; + private static final byte SESSION_DESTROY_FLAG_BYTE = (byte) (UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY << 4); + /** * @param transport may be null for unit testing only */ @@ -332,7 +346,7 @@ class PacketBuilder { int availableForExplicitAcks = availableForAcks; // make the packet - UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4)); + UDPPacket packet = buildPacketHeader(DATA_FLAG_BYTE); DatagramPacket pkt = packet.getPacket(); byte data[] = pkt.getData(); int off = HEADER_SIZE; @@ -573,7 +587,7 @@ class PacketBuilder { * @param ackBitfields list of ACKBitfield instances to either fully or partially ACK */ public UDPPacket buildACK(PeerState peer, List ackBitfields) { - UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4)); + UDPPacket packet = buildPacketHeader(DATA_FLAG_BYTE); DatagramPacket pkt = packet.getPacket(); byte data[] = pkt.getData(); int off = HEADER_SIZE; @@ -667,12 +681,6 @@ class PacketBuilder { return packet; } - /** - * full flag info for a sessionCreated message. this can be fixed, - * since we never rekey on startup, and don't need any extended options - */ - private static final byte SESSION_CREATED_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_SESSION_CREATED << 4); - /** * Build a new SessionCreated packet for the given peer, encrypting it * as necessary. @@ -768,12 +776,6 @@ class PacketBuilder { return packet; } - /** - * full flag info for a sessionRequest message. this can be fixed, - * since we never rekey on startup, and don't need any extended options - */ - private static final byte SESSION_REQUEST_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_SESSION_REQUEST << 4); - /** * Build a new SessionRequest packet for the given peer, encrypting it * as necessary. @@ -781,10 +783,23 @@ class PacketBuilder { * @return ready to send packet, or null if there was a problem */ public UDPPacket buildSessionRequestPacket(OutboundEstablishState state) { - UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE); + int off = HEADER_SIZE; + byte[] options; + boolean ext = state.isExtendedOptionsAllowed(); + if (ext) { + options = new byte[UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH]; + boolean intro = state.needIntroduction(); + if (intro) + options[1] = (byte) UDPPacket.SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG; + if (_log.shouldInfo()) + _log.info("send sess req. w/ ext. options, need intro? " + intro + ' ' + state); + off += UDPPacket.SESS_REQ_MIN_EXT_OPTIONS_LENGTH + 1; + } else { + options = null; + } + UDPPacket packet = buildPacketHeader(SESSION_REQUEST_FLAG_BYTE, options); DatagramPacket pkt = packet.getPacket(); byte data[] = pkt.getData(); - int off = HEADER_SIZE; byte toIP[] = state.getSentIP(); if (!_transport.isValid(toIP)) { @@ -854,13 +869,6 @@ class PacketBuilder { return packets; } - - /** - * full flag info for a sessionConfirmed message. this can be fixed, - * since we never rekey on startup, and don't need any extended options - */ - private static final byte SESSION_CONFIRMED_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_SESSION_CONFIRMED << 4); - /** * Build a new SessionConfirmed packet for the given peer * @@ -1018,7 +1026,7 @@ class PacketBuilder { * @since 0.9.2 */ private UDPPacket buildSessionDestroyPacket(SessionKey cipherKey, SessionKey macKey, InetAddress addr, int port) { - UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_SESSION_DESTROY << 4)); + UDPPacket packet = buildPacketHeader(SESSION_DESTROY_FLAG_BYTE); int off = HEADER_SIZE; // no body in this message @@ -1034,12 +1042,6 @@ class PacketBuilder { return packet; } - /** - * full flag info for a peerTest message. this can be fixed, - * since we never rekey on test, and don't need any extended options - */ - private static final byte PEER_TEST_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_TEST << 4); - /** * Build a packet as if we are Alice and we either want Bob to begin a * peer test or Charlie to finish a peer test. @@ -1197,12 +1199,6 @@ class PacketBuilder { packet.setMessageType(TYPE_TCB); return packet; } - - /** - * full flag info for a relay request message. this can be fixed, - * since we never rekey on relay request, and don't need any extended options - */ - private static final byte PEER_RELAY_REQUEST_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_RELAY_REQUEST << 4); // specify these if we know what our external receive ip/port is and if its different // from what bob is going to think @@ -1330,12 +1326,6 @@ class PacketBuilder { return packet; } - /** - * full flag info for a relay intro message. this can be fixed, - * since we never rekey on relay request, and don't need any extended options - */ - private static final byte PEER_RELAY_INTRO_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_RELAY_INTRO << 4); - UDPPacket buildRelayIntro(RemoteHostId alice, PeerState charlie, UDPPacketReader.RelayRequestReader request) { UDPPacket packet = buildPacketHeader(PEER_RELAY_INTRO_FLAG_BYTE); DatagramPacket pkt = packet.getPacket(); @@ -1370,12 +1360,6 @@ class PacketBuilder { packet.setMessageType(TYPE_INTRO); return packet; } - - /** - * full flag info for a relay response message. this can be fixed, - * since we never rekey on relay response, and don't need any extended options - */ - private static final byte PEER_RELAY_RESPONSE_FLAG_BYTE = (UDPPacket.PAYLOAD_TYPE_RELAY_RESPONSE << 4); UDPPacket buildRelayResponse(RemoteHostId alice, PeerState charlie, long nonce, SessionKey cipherKey, SessionKey macKey) { @@ -1462,24 +1446,50 @@ class PacketBuilder { /** * Create a new packet and add the flag byte and the time stamp. * Caller should add data starting at HEADER_SIZE. - * At this point, adding support for extended options and rekeying is unlikely, - * but if we do, we'll have to change this. + * Does not include extended options or rekeying. * * @param flagByte contains type and flags * @since 0.8.1 */ private UDPPacket buildPacketHeader(byte flagByte) { + return buildPacketHeader(flagByte, null); + } + + /** + * Create a new packet and add the flag byte and the time stamp. + * Caller should add data starting at HEADER_SIZE. + * (if extendedOptions != null, at HEADER_SIZE + 1 + extendedOptions.length) + * Does not include rekeying. + * + * @param flagByte contains type and flags + * @param extendedOptions May be null. If non-null, we will add the associated flag here. + * 255 bytes max. + * @since 0.9.24 + */ + private UDPPacket buildPacketHeader(byte flagByte, byte[] extendedOptions) { UDPPacket packet = UDPPacket.acquire(_context, false); byte data[] = packet.getPacket().getData(); Arrays.fill(data, 0, data.length, (byte)0x0); int off = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE; // header + if (extendedOptions != null) + flagByte |= UDPPacket.HEADER_FLAG_EXTENDED_OPTIONS; data[off] = flagByte; off++; + // Note, this is unsigned, so we're good until February 2106 long now = (_context.clock().now() + 500) / 1000; DataHelper.toLong(data, off, 4, now); - // todo: add support for rekeying and extended options + // todo: add support for rekeying + // extended options + if (extendedOptions != null) { + off+= 4; + int len = extendedOptions.length; + if (len > 255) + throw new IllegalArgumentException(); + data[off++] = (byte) len; + System.arraycopy(extendedOptions, 0, data, off, len); + } return packet; } diff --git a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java index 736171b80..1f5f990bc 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketHandler.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketHandler.java @@ -215,7 +215,7 @@ class PacketHandler { _state = 5; handlePacket(_reader, packet); _state = 6; - } catch (Exception e) { + } catch (RuntimeException e) { _state = 7; if (_log.shouldLog(Log.ERROR)) _log.error("Crazy error handling a packet: " + packet, e); diff --git a/router/java/src/net/i2p/router/transport/udp/PacketPusher.java b/router/java/src/net/i2p/router/transport/udp/PacketPusher.java index f28ee9645..5c770175c 100644 --- a/router/java/src/net/i2p/router/transport/udp/PacketPusher.java +++ b/router/java/src/net/i2p/router/transport/udp/PacketPusher.java @@ -43,7 +43,7 @@ class PacketPusher implements Runnable { send(packets.get(i)); } } - } catch (Exception e) { + } catch (RuntimeException e) { _log.error("SSU Output Queue Error", e); } } diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java index e2e1b3f59..238ec16fd 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -85,18 +85,38 @@ class UDPPacket implements CDQEntry { public static final int PAYLOAD_TYPE_RELAY_INTRO = 5; public static final int PAYLOAD_TYPE_DATA = 6; public static final int PAYLOAD_TYPE_TEST = 7; - public static final int MAX_PAYLOAD_TYPE = PAYLOAD_TYPE_TEST; /** @since 0.8.1 */ public static final int PAYLOAD_TYPE_SESSION_DESTROY = 8; + public static final int MAX_PAYLOAD_TYPE = PAYLOAD_TYPE_SESSION_DESTROY; + // various flag fields for use in the header + /** + * Defined in the spec from the beginning, Unused + * @since 0.9.24 + */ + public static final byte HEADER_FLAG_REKEY = (1 << 3); + /** + * Defined in the spec from the beginning, Used starting in 0.9.24 + * @since 0.9.24 + */ + public static final byte HEADER_FLAG_EXTENDED_OPTIONS = (1 << 2); + + // Extended options for session request + public static final int SESS_REQ_MIN_EXT_OPTIONS_LENGTH = 2; + // bytes 0-1 are flags + /** + * set to 1 to request a session tag, i.e. we want him to be an introducer for us + */ + public static final int SESS_REQ_EXT_FLAG_REQUEST_RELAY_TAG = 0x01; + // various flag fields for use in the data packets public static final byte DATA_FLAG_EXPLICIT_ACK = (byte)(1 << 7); public static final byte DATA_FLAG_ACK_BITFIELDS = (1 << 6); - // unused + /** unused */ public static final byte DATA_FLAG_ECN = (1 << 4); public static final byte DATA_FLAG_WANT_ACKS = (1 << 3); public static final byte DATA_FLAG_WANT_REPLY = (1 << 2); - // unused + /** unused */ public static final byte DATA_FLAG_EXTENDED = (1 << 1); public static final byte BITFIELD_CONTINUATION = (byte)(1 << 7); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java index adacea03f..c7c9d90cc 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java @@ -67,33 +67,68 @@ class UDPPacketReader { return (_message[_payloadBeginOffset] & 0xFF) >>> 4; } - /** does this packet include rekeying data? */ - public boolean readRekeying() { - return (_message[_payloadBeginOffset] & (1 << 3)) != 0; + /** + * Does this packet include rekeying data in the header? + * Unused, should always be false. + */ + public boolean isRekeyingIncluded() { + return (_message[_payloadBeginOffset] & UDPPacket.HEADER_FLAG_REKEY) != 0; } - public boolean readExtendedOptionsIncluded() { - return (_message[_payloadBeginOffset] & (1 << 2)) != 0; + /** + * Does this packet include extended options in the header? + */ + public boolean isExtendedOptionsIncluded() { + return (_message[_payloadBeginOffset] & UDPPacket.HEADER_FLAG_EXTENDED_OPTIONS) != 0; } /** @return seconds */ public long readTimestamp() { + // Note, this is unsigned, so we're good until February 2106 return DataHelper.fromLong(_message, _payloadBeginOffset + 1, 4); } - public void readKeyingMaterial(byte target[], int targetOffset) { - if (!readRekeying()) - throw new IllegalStateException("This packet is not rekeying!"); - System.arraycopy(_message, _payloadBeginOffset + 1 + 4, target, targetOffset, KEYING_MATERIAL_LENGTH); + /** + * Returns rekeying data (64 bytes), or null if none. + * Unused, should always return null. + * + * @deprecated unused + */ + @Deprecated + public byte[] readKeyingMaterial() { + if (!isRekeyingIncluded()) + return null; + byte[] rv = new byte[KEYING_MATERIAL_LENGTH]; + System.arraycopy(_message, _payloadBeginOffset + 1 + 4, rv, 0, KEYING_MATERIAL_LENGTH); + return rv; + } + + /** + * Returns extended option data, 0-255 bytes, or null if none. + * Returned array does NOT include the length byte. + * + * @return extended options or null if none is included + * @since 0.9.24 + */ + public byte[] readExtendedOptions() { + if (!isExtendedOptionsIncluded()) + return null; + int offset = _payloadBeginOffset + 1 + 4; + if (isRekeyingIncluded()) + offset += KEYING_MATERIAL_LENGTH; + int optionsSize = _message[offset++] & 0xff; + byte[] rv = new byte[optionsSize]; + System.arraycopy(_message, offset, rv, 0, optionsSize); + return rv; } /** index into the message where the body begins */ private int readBodyOffset() { int offset = _payloadBeginOffset + 1 + 4; - if (readRekeying()) + if (isRekeyingIncluded()) offset += KEYING_MATERIAL_LENGTH; - if (readExtendedOptionsIncluded()) { - int optionsSize = (int)DataHelper.fromLong(_message, offset, 1); + if (isExtendedOptionsIncluded()) { + int optionsSize = _message[offset] & 0xff; offset += optionsSize + 1; } return offset; @@ -142,8 +177,26 @@ class UDPPacketReader { /* ------- Begin Reader Classes ------- */ + /** + * Base + * + * @since 0.9.24 + */ + public abstract class Reader { + /** + * Returns extended option data from the header, 0-255 bytes, or null if none. + * Returned array does NOT include the length byte. + * + * @return extended options or null if none is included + * @since 0.9.24 + */ + public byte[] readExtendedOptions() { + return UDPPacketReader.this.readExtendedOptions(); + } + } + /** Help read the SessionRequest payload */ - public class SessionRequestReader { + public class SessionRequestReader extends Reader { public static final int X_LENGTH = 256; public void readX(byte target[], int targetOffset) { int readOffset = readBodyOffset(); @@ -152,20 +205,20 @@ class UDPPacketReader { public int readIPSize() { int offset = readBodyOffset() + X_LENGTH; - return (int)DataHelper.fromLong(_message, offset, 1); + return _message[offset] & 0xff; } /** what IP bob is reachable on */ public void readIP(byte target[], int targetOffset) { int offset = readBodyOffset() + X_LENGTH; - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, size); } } /** Help read the SessionCreated payload */ - public class SessionCreatedReader { + public class SessionCreatedReader extends Reader { public static final int Y_LENGTH = 256; public void readY(byte target[], int targetOffset) { int readOffset = readBodyOffset(); @@ -175,13 +228,13 @@ class UDPPacketReader { /** sizeof(IP) */ public int readIPSize() { int offset = readBodyOffset() + Y_LENGTH; - return (int)DataHelper.fromLong(_message, offset, 1); + return _message[offset] & 0xff; } /** what IP do they think we are coming on? */ public void readIP(byte target[], int targetOffset) { int offset = readBodyOffset() + Y_LENGTH; - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, size); } @@ -220,7 +273,7 @@ class UDPPacketReader { } /** parse out the confirmed message */ - public class SessionConfirmedReader { + public class SessionConfirmedReader extends Reader { /** which fragment is this? */ public int readCurrentFragmentNum() { int readOffset = readBodyOffset(); @@ -273,7 +326,7 @@ class UDPPacketReader { } /** parse out the data message */ - public class DataReader { + public class DataReader extends Reader { /** * @return the data size, NOT including IP header, UDP header, IV, or MAC @@ -307,7 +360,7 @@ class UDPPacketReader { public int readACKCount() { if (!readACKsIncluded()) return 0; int off = readBodyOffset() + 1; - return (int)DataHelper.fromLong(_message, off, 1); + return _message[off] & 0xff; } public long readACK(int index) { @@ -322,12 +375,12 @@ class UDPPacketReader { if (!readACKBitfieldsIncluded()) return null; int off = readBodyOffset() + 1; if (readACKsIncluded()) { - int numACKs = (int)DataHelper.fromLong(_message, off, 1); + int numACKs = _message[off] & 0xff; off++; off += 4 * numACKs; } - int numBitfields = (int)DataHelper.fromLong(_message, off, 1); + int numBitfields = _message[off] & 0xff; off++; PacketACKBitfield rv[] = new PacketACKBitfield[numBitfields]; @@ -341,12 +394,12 @@ class UDPPacketReader { public int readFragmentCount() throws DataFormatException { int off = readBodyOffset() + 1; if (readACKsIncluded()) { - int numACKs = (int)DataHelper.fromLong(_message, off, 1); + int numACKs = _message[off] & 0xff; off++; off += 4 * numACKs; } if (readACKBitfieldsIncluded()) { - int numBitfields = (int)DataHelper.fromLong(_message, off, 1); + int numBitfields = _message[off] & 0xff; off++; for (int i = 0; i < numBitfields; i++) { @@ -355,7 +408,7 @@ class UDPPacketReader { } } if (readExtendedDataIncluded()) { - int size = (int)DataHelper.fromLong(_message, off, 1); + int size = _message[off] & 0xff; off++; off += size; } @@ -397,12 +450,12 @@ class UDPPacketReader { private int getFragmentBegin(int fragmentNum) throws DataFormatException { int off = readBodyOffset() + 1; if (readACKsIncluded()) { - int numACKs = (int)DataHelper.fromLong(_message, off, 1); + int numACKs = _message[off] & 0xff; off++; off += 4 * numACKs; } if (readACKBitfieldsIncluded()) { - int numBitfields = (int)DataHelper.fromLong(_message, off, 1); + int numBitfields = _message[off] & 0xff; off++; PacketACKBitfield bf[] = new PacketACKBitfield[numBitfields]; @@ -412,7 +465,7 @@ class UDPPacketReader { } } if (readExtendedDataIncluded()) { - int size = (int)DataHelper.fromLong(_message, off, 1); + int size = _message[off] & 0xff; off++; off += size; } @@ -443,7 +496,7 @@ class UDPPacketReader { buf.append(" "); int off = readBodyOffset() + 1; if (readACKsIncluded()) { - int numACKs = (int)DataHelper.fromLong(_message, off, 1); + int numACKs = _message[off] & 0xff; off++; buf.append("with ACKs for "); for (int i = 0; i < numACKs; i++) { @@ -452,7 +505,7 @@ class UDPPacketReader { } } if (readACKBitfieldsIncluded()) { - int numBitfields = (int)DataHelper.fromLong(_message, off, 1); + int numBitfields = _message[off] & 0xff; off++; buf.append("with partial ACKs for "); @@ -468,7 +521,7 @@ class UDPPacketReader { } } if (readExtendedDataIncluded()) { - int size = (int)DataHelper.fromLong(_message, off, 1); + int size = _message[off] & 0xff; off++; buf.append("with extended size of "); buf.append(size); @@ -476,7 +529,7 @@ class UDPPacketReader { off += size; } - int numFragments = (int)DataHelper.fromLong(_message, off, 1); + int numFragments = _message[off] & 0xff; off++; buf.append("with fragmentCount of "); buf.append(numFragments); @@ -506,8 +559,7 @@ class UDPPacketReader { buf.append(" payload: "); int off = getFragmentBegin(0); // first fragment - off += 4; // messageId - off++; // fragment info + off += 4 + 1; // messageId + fragment info int size = ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF; off += 2; buf.append(Base64.encode(_message, off, size)); @@ -610,7 +662,7 @@ class UDPPacketReader { } /** Help read the PeerTest payload */ - public class PeerTestReader { + public class PeerTestReader extends Reader { private static final int NONCE_LENGTH = 4; public long readNonce() { @@ -620,13 +672,13 @@ class UDPPacketReader { public int readIPSize() { int offset = readBodyOffset() + NONCE_LENGTH; - return (int)DataHelper.fromLong(_message, offset, 1); + return _message[offset] & 0xff; } /** what IP Alice is reachable on */ public void readIP(byte target[], int targetOffset) { int offset = readBodyOffset() + NONCE_LENGTH; - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, size); } @@ -634,7 +686,7 @@ class UDPPacketReader { /** what IP Alice is reachable on */ public int readPort() { int offset = readBodyOffset() + NONCE_LENGTH; - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; offset += size; // skip the IP return (int)DataHelper.fromLong(_message, offset, 2); @@ -643,16 +695,15 @@ class UDPPacketReader { /** what Alice's intro key is (if known - if unknown, the key is INVALID_KEY) */ public void readIntroKey(byte target[], int targetOffset) { int offset = readBodyOffset() + NONCE_LENGTH; - int size = (int)DataHelper.fromLong(_message, offset, 1); - offset++; + int size = _message[offset] & 0xff; + offset += 1 + 2; // skip the size + port offset += size; // skip the IP - offset += 2; // skip the port System.arraycopy(_message, offset, target, targetOffset, SessionKey.KEYSIZE_BYTES); } } /** Help read the RelayRequest payload */ - public class RelayRequestReader { + public class RelayRequestReader extends Reader { public long readTag() { long rv = DataHelper.fromLong(_message, readBodyOffset(), 4); if (_log.shouldLog(Log.DEBUG)) @@ -661,7 +712,7 @@ class UDPPacketReader { } public int readIPSize() { int offset = readBodyOffset() + 4; - int rv = (int)DataHelper.fromLong(_message, offset, 1); + int rv = _message[offset] & 0xff; if (_log.shouldLog(Log.DEBUG)) _log.debug("read alice ip size: " + rv); return rv; @@ -670,7 +721,7 @@ class UDPPacketReader { /** what IP Alice is reachable on */ public void readIP(byte target[], int targetOffset) { int offset = readBodyOffset() + 4; - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, size); if (_log.shouldLog(Log.DEBUG)) @@ -678,7 +729,7 @@ class UDPPacketReader { } public int readPort() { int offset = readBodyOffset() + 4; - offset += DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; offset++; int rv = (int)DataHelper.fromLong(_message, offset, 2); if (_log.shouldLog(Log.DEBUG)) @@ -689,10 +740,9 @@ class UDPPacketReader { /** unused */ public int readChallengeSize() { int offset = readBodyOffset() + 4; - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int rv = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int rv = _message[offset] & 0xff; if (_log.shouldLog(Log.DEBUG)) _log.debug("read challenge size: " + rv); return rv; @@ -701,10 +751,9 @@ class UDPPacketReader { /** unused */ public void readChallengeSize(byte target[], int targetOffset) { int offset = readBodyOffset() + 4; - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, sz); if (_log.shouldLog(Log.DEBUG)) @@ -712,10 +761,9 @@ class UDPPacketReader { } public void readAliceIntroKey(byte target[], int targetOffset) { int offset = readBodyOffset() + 4; - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; offset++; offset += sz; System.arraycopy(_message, offset, target, targetOffset, SessionKey.KEYSIZE_BYTES); @@ -725,10 +773,9 @@ class UDPPacketReader { } public long readNonce() { int offset = readBodyOffset() + 4; - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; offset++; offset += sz; offset += SessionKey.KEYSIZE_BYTES; @@ -740,22 +787,22 @@ class UDPPacketReader { } /** Help read the RelayIntro payload */ - public class RelayIntroReader { + public class RelayIntroReader extends Reader { public int readIPSize() { int offset = readBodyOffset(); - return (int)DataHelper.fromLong(_message, offset, 1); + return _message[offset] & 0xff; } /** what IP Alice is reachable on */ public void readIP(byte target[], int targetOffset) { int offset = readBodyOffset(); - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, size); } public int readPort() { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; offset++; return (int)DataHelper.fromLong(_message, offset, 2); } @@ -763,19 +810,17 @@ class UDPPacketReader { /** unused */ public int readChallengeSize() { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - return (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + return _message[offset] & 0xff; } /** unused */ public void readChallengeSize(byte target[], int targetOffset) { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, sz); } @@ -783,22 +828,22 @@ class UDPPacketReader { /** Help read the RelayResponse payload */ - public class RelayResponseReader { + public class RelayResponseReader extends Reader { public int readCharlieIPSize() { int offset = readBodyOffset(); - return (int)DataHelper.fromLong(_message, offset, 1); + return _message[offset] & 0xff; } /** what IP charlie is reachable on */ public void readCharlieIP(byte target[], int targetOffset) { int offset = readBodyOffset(); - int size = (int)DataHelper.fromLong(_message, offset, 1); + int size = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, size); } /** what port charlie is reachable on */ public int readCharliePort() { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; offset++; return (int)DataHelper.fromLong(_message, offset, 2); } @@ -806,41 +851,36 @@ class UDPPacketReader { /** @deprecated unused */ public int readAliceIPSize() { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - return (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + return _message[offset] & 0xff; } /** @deprecated unused */ public void readAliceIP(byte target[], int targetOffset) { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; offset++; System.arraycopy(_message, offset, target, targetOffset, sz); } /** @deprecated unused */ public int readAlicePort() { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; offset++; offset += sz; return (int)DataHelper.fromLong(_message, offset, 2); } public long readNonce() { int offset = readBodyOffset(); - offset += DataHelper.fromLong(_message, offset, 1); - offset++; - offset += 2; - int sz = (int)DataHelper.fromLong(_message, offset, 1); - offset++; + offset += _message[offset] & 0xff; + offset += 1 + 2; + int sz = _message[offset] & 0xff; + offset += 1 + 2; // sz + port offset += sz; - offset += 2; return DataHelper.fromLong(_message, offset, 4); } } 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 edcfef26b..f6a94d7fb 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -340,7 +340,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority List bindToAddrs = new ArrayList(4); if (bindTo != null) { - String[] bta = bindTo.split("[,; \r\n\t]"); + String[] bta = DataHelper.split(bindTo, "[,; \r\n\t]"); for (int i = 0; i < bta.length; i++) { String bt = bta[i]; if (bt.length() <= 0) @@ -1896,7 +1896,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority if (explicitAddressSpecified()) { host = _context.getProperty(PROP_EXTERNAL_HOST); if (host != null) { - String[] hosts = host.split("[,; \r\n\t]"); + String[] hosts = DataHelper.split(host, "[,; \r\n\t]"); RouterAddress rv = null; for (int i = 0; i < hosts.length; i++) { String h = hosts[i]; @@ -2216,6 +2216,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority if (_log.shouldLog(Log.DEBUG)) _log.debug("Require introducers, because our status is " + status); return true; + default: if (!allowDirectUDP()) { if (_log.shouldLog(Log.DEBUG)) @@ -2226,6 +2227,30 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } + /** + * MIGHT we require introducers? + * This is like introducersRequired, but if we aren't sure, this returns true. + * Used only by EstablishmentManager. + * + * @since 0.9.24 + */ + boolean introducersMaybeRequired() { + Status status = getReachabilityStatus(); + switch (status) { + case REJECT_UNSOLICITED: + case DIFFERENT: + case IPV4_FIREWALLED_IPV6_OK: + case IPV4_FIREWALLED_IPV6_UNKNOWN: + case IPV4_UNKNOWN_IPV6_OK: + case IPV4_UNKNOWN_IPV6_FIREWALLED: + case UNKNOWN: + return true; + + default: + return !allowDirectUDP(); + } + } + /** * For EstablishmentManager * @since 0.9.3 diff --git a/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java b/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java index 2196a851e..8514d6db1 100644 --- a/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java +++ b/router/java/src/net/i2p/router/tunnel/BuildReplyHandler.java @@ -120,7 +120,7 @@ public class BuildReplyHandler { return -1; } else { SimpleByteCache.release(h); - int rv = (int)DataHelper.fromLong(data, TunnelBuildReplyMessage.RECORD_SIZE - 1, 1); + int rv = data[TunnelBuildReplyMessage.RECORD_SIZE - 1] & 0xff; if (log.shouldLog(Log.DEBUG)) log.debug(reply.getUniqueId() + ": Verified: " + rv + " for record " + recordNum + "/" + hop); return rv; diff --git a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java index 6e0d0675f..eef132712 100644 --- a/router/java/src/net/i2p/router/tunnel/FragmentHandler.java +++ b/router/java/src/net/i2p/router/tunnel/FragmentHandler.java @@ -340,7 +340,7 @@ class FragmentHandler { offset += 4; } if (extended) { - int extendedSize = (int)DataHelper.fromLong(preprocessed, offset, 1); + int extendedSize = preprocessed[offset] & 0xff; offset++; offset += extendedSize; // we don't interpret these yet, but skip them for now } diff --git a/router/java/src/net/i2p/router/tunnel/HopConfig.java b/router/java/src/net/i2p/router/tunnel/HopConfig.java index 0e317cd79..3045c3371 100644 --- a/router/java/src/net/i2p/router/tunnel/HopConfig.java +++ b/router/java/src/net/i2p/router/tunnel/HopConfig.java @@ -51,12 +51,14 @@ public class HopConfig { public void setReceiveTunnelId(byte id[]) { _receiveTunnelId = id; } public void setReceiveTunnelId(TunnelId id) { _receiveTunnelId = DataHelper.toLong(4, id.getTunnelId()); } - /** what is the previous peer in the tunnel (if any)? */ + /** what is the previous peer in the tunnel (null if gateway) */ public Hash getReceiveFrom() { return _receiveFrom; } public void setReceiveFrom(Hash from) { _receiveFrom = from; } - /** what is the next tunnel ID we are sending to? */ + /** what is the next tunnel ID we are sending to? (null if endpoint) */ public byte[] getSendTunnelId() { return _sendTunnelId; } + + /** what is the next tunnel we are sending to? (null if endpoint) */ public TunnelId getSendTunnel() { if (_sendTunnel == null) _sendTunnel = getTunnel(_sendTunnelId); @@ -71,7 +73,7 @@ public class HopConfig { return new TunnelId(DataHelper.fromLong(id, 0, id.length)); } - /** what is the next peer in the tunnel (if any)? */ + /** what is the next peer in the tunnel (null if endpoint) */ public Hash getSendTo() { return _sendTo; } public void setSendTo(Hash to) { _sendTo = to; } diff --git a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java index 9340477c6..758d2096b 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelCreatorConfig.java @@ -30,16 +30,32 @@ public class TunnelCreatorConfig implements TunnelInfo { private long _replyMessageId; private final boolean _isInbound; private int _messagesProcessed; - private volatile long _verifiedBytesTransferred; + private long _verifiedBytesTransferred; private boolean _failed; private int _failures; private boolean _reused; private int _priority; + //private static final int THROUGHPUT_COUNT = 3; + // Fastest 1 minute throughput, in bytes per minute, ordered with fastest first. + //private final double _peakThroughput[] = new double[THROUGHPUT_COUNT]; + private long _peakThroughputCurrentTotal; + private long _peakThroughputLastCoallesce = System.currentTimeMillis(); + // Make configurable? - but can't easily get to pool options from here + private static final int MAX_CONSECUTIVE_TEST_FAILURES = 3; + private static final SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss", Locale.UK); + /** + * For exploratory only (null destination) + * @param length 1 minimum (0 hop is length 1) + */ public TunnelCreatorConfig(RouterContext ctx, int length, boolean isInbound) { this(ctx, length, isInbound, null); } + /** + * @param length 1 minimum (0 hop is length 1) + * @param destination null for exploratory + */ public TunnelCreatorConfig(RouterContext ctx, int length, boolean isInbound, Hash destination) { _context = ctx; if (length <= 0) @@ -131,10 +147,14 @@ public class TunnelCreatorConfig implements TunnelInfo { public void setReplyMessageId(long id) { _replyMessageId = id; } /** take note of a message being pumped through this tunnel */ - public void incrementProcessedMessages() { _messagesProcessed++; } - public int getProcessedMessagesCount() { return _messagesProcessed; } + public synchronized void incrementProcessedMessages() { _messagesProcessed++; } + public synchronized int getProcessedMessagesCount() { return _messagesProcessed; } - public void incrementVerifiedBytesTransferred(int bytes) { + /** + * This calls profile manager tunnelDataPushed1m() for each peer + * @return null for exploratory + */ + public synchronized void incrementVerifiedBytesTransferred(int bytes) { _verifiedBytesTransferred += bytes; _peakThroughputCurrentTotal += bytes; long now = System.currentTimeMillis(); @@ -144,38 +164,34 @@ public class TunnelCreatorConfig implements TunnelInfo { double normalized = tot * 60d*1000d / timeSince; _peakThroughputLastCoallesce = now; _peakThroughputCurrentTotal = 0; - if (_context != null) - for (int i = 0; i < _peers.length; i++) + if (_context != null) { + // skip ourselves + int start = _isInbound ? 0 : 1; + int end = _isInbound ? _peers.length - 1 : _peers.length; + for (int i = start; i < end; i++) { _context.profileManager().tunnelDataPushed1m(_peers[i], (int)normalized); + } + } } } - public long getVerifiedBytesTransferred() { return _verifiedBytesTransferred; } + public synchronized long getVerifiedBytesTransferred() { return _verifiedBytesTransferred; } - private static final int THROUGHPUT_COUNT = 3; - /** - * fastest 1 minute throughput, in bytes per minute, ordered with fastest - * first. - */ - private final double _peakThroughput[] = new double[THROUGHPUT_COUNT]; - private volatile long _peakThroughputCurrentTotal; - private volatile long _peakThroughputLastCoallesce = System.currentTimeMillis(); - public double getPeakThroughputKBps() { +/**** unused + public synchronized double getPeakThroughputKBps() { double rv = 0; for (int i = 0; i < THROUGHPUT_COUNT; i++) rv += _peakThroughput[i]; rv /= (60d*1024d*THROUGHPUT_COUNT); return rv; } - public void setPeakThroughputKBps(double kBps) { + + public synchronized void setPeakThroughputKBps(double kBps) { _peakThroughput[0] = kBps*60*1024; //for (int i = 0; i < THROUGHPUT_COUNT; i++) // _peakThroughput[i] = kBps*60; } - - - // Make configurable? - but can't easily get to pool options from here - private static final int MAX_CONSECUTIVE_TEST_FAILURES = 3; +****/ /** * The tunnel failed a test, so (maybe) stop using it @@ -264,11 +280,10 @@ public class TunnelCreatorConfig implements TunnelInfo { return buf.toString(); } - private static final SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss", Locale.UK); - private String getExpirationString() { return format(_expiration); } + static String format(long date) { Date d = new Date(date); synchronized (_fmt) { diff --git a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java index 8e4d43335..6c80375ed 100644 --- a/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java +++ b/router/java/src/net/i2p/router/tunnel/TunnelDispatcher.java @@ -457,7 +457,8 @@ public class TunnelDispatcher implements Service { _inboundGateways.remove(recvId); } else { // update stats based off getCompleteCount() + getFailedCount() - for (int i = 0; i < cfg.getLength(); i++) { + // skip last hop (us) + for (int i = 0; i < cfg.getLength() - 1; i++) { Hash peer = cfg.getPeer(i); PeerProfile profile = _context.profileOrganizer().getProfile(peer); if (profile != null) { diff --git a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java index 5b2bdfb2a..0848bbe1b 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java +++ b/router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java @@ -213,7 +213,7 @@ class BuildHandler implements Runnable { while (_isRunning && !_manager.isShutdown()) { try { handleInboundRequest(); - } catch (Exception e) { + } catch (RuntimeException e) { _log.log(Log.CRIT, "B0rked in the tunnel handler", e); } } @@ -795,7 +795,8 @@ class BuildHandler implements Runnable { cfg.setIVKey(req.readIVKey()); cfg.setLayerKey(req.readLayerKey()); if (isInGW) { - cfg.setReceiveFrom(null); + // default + //cfg.setReceiveFrom(null); } else { if (state.fromHash != null) { cfg.setReceiveFrom(state.fromHash); @@ -808,8 +809,9 @@ class BuildHandler implements Runnable { } cfg.setReceiveTunnelId(DataHelper.toLong(4, ourId)); if (isOutEnd) { - cfg.setSendTo(null); - cfg.setSendTunnelId(null); + // default + //cfg.setSendTo(null); + //cfg.setSendTunnelId(null); } else { cfg.setSendTo(nextPeer); cfg.setSendTunnelId(DataHelper.toLong(4, nextId)); diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java index a1dae253c..aaf24387c 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPool.java @@ -1168,7 +1168,7 @@ public class TunnelPool { int j = peers.size() - 1 - i; cfg.setPeer(j, peers.get(i)); HopConfig hop = cfg.getConfig(j); - hop.setCreation(_context.clock().now()); + hop.setCreation(now); hop.setExpiration(expiration); hop.setIVKey(_context.keyGenerator().generateSessionKey()); hop.setLayerKey(_context.keyGenerator().generateSessionKey()); diff --git a/router/java/src/net/i2p/router/util/EventLog.java b/router/java/src/net/i2p/router/util/EventLog.java index 1cad4b9b4..14f829dbe 100644 --- a/router/java/src/net/i2p/router/util/EventLog.java +++ b/router/java/src/net/i2p/router/util/EventLog.java @@ -13,6 +13,7 @@ import java.util.SortedMap; import java.util.TreeMap; import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; import net.i2p.util.SecureFileOutputStream; /** @@ -125,7 +126,7 @@ public class EventLog { String line = null; while ( (line = br.readLine()) != null) { try { - String[] s = line.split(" ", 3); + String[] s = DataHelper.split(line, " ", 3); if (!s[1].equals(event)) continue; long time = Long.parseLong(s[0]); @@ -167,7 +168,7 @@ public class EventLog { String line = null; while ( (line = br.readLine()) != null) { try { - String[] s = line.split(" ", 2); + String[] s = DataHelper.split(line, " ", 2); if (s.length < 2) continue; long time = Long.parseLong(s[0]);