diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 2869193a0a703344af2867123b60bcb884c26932..8ffde7363b9fbcf158d3009e00fbad4be62ec1fa 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -215,7 +215,7 @@ class PeerCoordinator implements PeerListener public Storage getStorage() { return storage; } - // for web page detailed stats + /** for web page detailed stats */ public List<Peer> peerList() { return new ArrayList(peers); @@ -446,6 +446,12 @@ class PeerCoordinator implements PeerListener synchronized (downloaded_old) { Arrays.fill(downloaded_old, 0); } + // failsafe + synchronized(wantedPieces) { + for (Piece pc : wantedPieces) { + pc.clear(); + } + } timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD)); } @@ -750,8 +756,12 @@ class PeerCoordinator implements PeerListener // AND if there are almost no wanted pieces left (real end game). // If we do end game all the time, we generate lots of extra traffic // when the seeder is super-slow and all the peers are "caught up" - if (wantedSize > END_GAME_THRESHOLD) + if (wantedSize > END_GAME_THRESHOLD) { + if (_log.shouldLog(Log.INFO)) + _log.info("Nothing to request, " + requested.size() + " being requested and " + + wantedSize + " still wanted"); return null; // nothing to request and not in end game + } // let's not all get on the same piece // Even better would be to sort by number of requests if (record) @@ -1078,10 +1088,11 @@ class PeerCoordinator implements PeerListener /** Called when a peer is removed, to prevent it from being used in * rarest-first calculations. */ - public void removePeerFromPieces(Peer peer) { + private void removePeerFromPieces(Peer peer) { synchronized(wantedPieces) { for (Piece piece : wantedPieces) { piece.removePeer(peer); + piece.setRequested(peer, false); } } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index 8f80d449644aefbad1990abb3bc57458e2746044..95bef3c4f981c0fbef55be361769790724dd12c4 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -682,6 +682,7 @@ class PeerState implements DataLoader _log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()"); return; } + // huh? rv unused more_pieces = requestNextPiece(); } else if (more_pieces) // We want something { @@ -711,6 +712,8 @@ class PeerState implements DataLoader } // failsafe + // However this is bad as it thrashes the peer when we change our mind + // Ticket 691 cause here? if (interesting && lastRequest == null && outstandingRequests.isEmpty()) setInteresting(false); @@ -784,6 +787,8 @@ class PeerState implements DataLoader } // failsafe + // However this is bad as it thrashes the peer when we change our mind + // Ticket 691 cause here? if (outstandingRequests.isEmpty()) lastRequest = null; diff --git a/apps/i2psnark/java/src/org/klomp/snark/Piece.java b/apps/i2psnark/java/src/org/klomp/snark/Piece.java index 3ca03ad98865bbf976336ecd225ed86bc59bcc73..9a2e2e0e75344c75935ff8729b59c3d6b41a4204 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Piece.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Piece.java @@ -12,7 +12,7 @@ class Piece implements Comparable { private final int id; private final Set<PeerID> peers; /** @since 0.8.3 */ - private Set<PeerID> requests; + private volatile Set<PeerID> requests; /** @since 0.8.1 */ private int priority; @@ -54,7 +54,10 @@ class Piece implements Comparable { /** caller must synchronize */ public boolean addPeer(Peer peer) { return this.peers.add(peer.getPeerID()); } - /** caller must synchronize */ + /** + * Caller must synchronize. + * @return true if removed + */ public boolean removePeer(Peer peer) { return this.peers.remove(peer.getPeerID()); } /** @@ -104,6 +107,17 @@ class Piece implements Comparable { public int getRequestCount() { return this.requests == null ? 0 : this.requests.size(); } + + /** + * Clear all knowledge of peers + * Caller must synchronize + * @since 0.9.3 + */ + public void clear() { + peers.clear(); + if (requests != null) + requests.clear(); + } /** @return default 0 @since 0.8.1 */ public int getPriority() { return this.priority; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java index 34c2174a9a1292530b954ab1d8c95b26e776925a..a811e05b94de7ed1dc31d0a7c9c71614918853d2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/RouterConsoleRunner.java @@ -38,11 +38,14 @@ import net.i2p.util.PortMapper; import net.i2p.util.SecureDirectory; import net.i2p.util.SecureFileOutputStream; import net.i2p.util.ShellCommand; +import net.i2p.util.SystemVersion; import net.i2p.util.VersionComparator; +import org.mortbay.jetty.AbstractConnector; import org.mortbay.jetty.Connector; import org.mortbay.jetty.NCSARequestLog; import org.mortbay.jetty.Server; +import org.mortbay.jetty.bio.SocketConnector; import org.mortbay.jetty.handler.ContextHandlerCollection; import org.mortbay.jetty.handler.DefaultHandler; import org.mortbay.jetty.handler.HandlerCollection; @@ -54,6 +57,7 @@ import org.mortbay.jetty.security.HashUserRealm; import org.mortbay.jetty.security.Constraint; import org.mortbay.jetty.security.ConstraintMapping; import org.mortbay.jetty.security.SecurityHandler; +import org.mortbay.jetty.security.SslSocketConnector; import org.mortbay.jetty.security.SslSelectChannelConnector; import org.mortbay.jetty.servlet.ServletHandler; import org.mortbay.jetty.servlet.ServletHolder; @@ -240,8 +244,7 @@ public class RouterConsoleRunner implements RouterApp { try { //TODO: move away from routerconsole into a separate application. //ApplicationManager? - VersionComparator v = new VersionComparator(); - boolean recentJava = v.compare(System.getProperty("java.runtime.version"), "1.6") >= 0; + boolean recentJava = SystemVersion.isJava6(); // default false for now boolean desktopguiEnabled = ctx.getBooleanProperty("desktopgui.enabled"); if (recentJava && desktopguiEnabled) { @@ -397,12 +400,22 @@ public class RouterConsoleRunner implements RouterApp { // _server.addListener('[' + host + "]:" + _listenPort); //else // _server.addListener(host + ':' + _listenPort); - SelectChannelConnector lsnr = new SelectChannelConnector(); + AbstractConnector lsnr; + if (SystemVersion.isJava6() && !SystemVersion.isGNU()) { + SelectChannelConnector slsnr = new SelectChannelConnector(); + slsnr.setUseDirectBuffers(false); // default true seems to be leaky + lsnr = slsnr; + } else { + // Jetty 6 and NIO on Java 5 don't get along that well + // Also: http://jira.codehaus.org/browse/JETTY-1238 + // "Do not use GCJ with Jetty, it will not work." + // Actually it does if you don't use NIO + lsnr = new SocketConnector(); + } lsnr.setHost(host); lsnr.setPort(lport); lsnr.setMaxIdleTime(90*1000); // default 10 sec lsnr.setName("ConsoleSocket"); // all with same name will use the same thread pool - lsnr.setUseDirectBuffers(false); // default true seems to be leaky //_server.addConnector(lsnr); connectors.add(lsnr); boundAddresses++; @@ -451,22 +464,37 @@ public class RouterConsoleRunner implements RouterApp { } // TODO if class not found use SslChannelConnector // Sadly there's no common base class with the ssl methods in it - SslSelectChannelConnector ssll = new SslSelectChannelConnector(); - ssll.setHost(host); - ssll.setPort(sslPort); + AbstractConnector ssll; + if (SystemVersion.isJava6() && !SystemVersion.isGNU()) { + SslSelectChannelConnector sssll = new SslSelectChannelConnector(); + // the keystore path and password + sssll.setKeystore(keyStore.getAbsolutePath()); + sssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD)); + // the X.509 cert password (if not present, verifyKeyStore() returned false) + sssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork")); + sssll.setUseDirectBuffers(false); // default true seems to be leaky + ssll = sssll; + } else { + // Jetty 6 and NIO on Java 5 don't get along that well + SslSocketConnector sssll = new SslSocketConnector(); // the keystore path and password - ssll.setKeystore(keyStore.getAbsolutePath()); - ssll.setPassword(_context.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD)); + sssll.setKeystore(keyStore.getAbsolutePath()); + sssll.setPassword(ctx.getProperty(PROP_KEYSTORE_PASSWORD, DEFAULT_KEYSTORE_PASSWORD)); // the X.509 cert password (if not present, verifyKeyStore() returned false) - ssll.setKeyPassword(_context.getProperty(PROP_KEY_PASSWORD, "thisWontWork")); + sssll.setKeyPassword(ctx.getProperty(PROP_KEY_PASSWORD, "thisWontWork")); + ssll = sssll; + } + ssll.setHost(host); + ssll.setPort(sslPort); ssll.setMaxIdleTime(90*1000); // default 10 sec ssll.setName("ConsoleSocket"); // all with same name will use the same thread pool - ssll.setUseDirectBuffers(false); // default true seems to be leaky //_server.addConnector(ssll); connectors.add(ssll); boundAddresses++; } catch (Exception e) { System.err.println("Unable to bind routerconsole to " + host + " port " + sslPort + " for SSL: " + e); + if (SystemVersion.isGNU()) + System.err.println("Probably because GNU classpath does not support Sun keystores"); System.err.println("You may ignore this warning if the console is still available at https://localhost:" + sslPort); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java index 825133c0eeb4cb3bb8d89f513519d53f281fb5f0..199cf5e4e3bec88e52217a581c6641f0d7b954e6 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatSummarizer.java @@ -67,12 +67,10 @@ public class StatSummarizer implements Runnable { public void run() { // JRobin 1.5.9 crashes these JVMs - String vendor = System.getProperty("java.vendor"); - if (vendor.startsWith("Apache") || // Harmony - vendor.startsWith("GNU Classpath") || // JamVM - vendor.startsWith("Free Software Foundation")) { // gij + if (SystemVersion.isApache() || // Harmony + SystemVersion.isGNU()) { // JamVM or gij _log.logAlways(Log.WARN, "Graphing not supported with this JVM: " + - vendor + ' ' + + System.getProperty("java.vendor") + ' ' + System.getProperty("java.version") + " (" + System.getProperty("java.runtime.name") + ' ' + System.getProperty("java.runtime.version") + ')'); 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 c520a2bb5635dc943cdafe7d2f86a87f7031ff6e..99a64df949764cb84a6e2a544a1b0edaee240e05 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -456,10 +456,11 @@ public class SummaryHelper extends HelperBase { /** compare translated nicknames - put "shared clients" first in the sort */ private class AlphaComparator implements Comparator<Destination> { + private final String xsc = _("shared clients"); + public int compare(Destination lhs, Destination rhs) { String lname = getName(lhs); String rname = getName(rhs); - String xsc = _("shared clients"); if (lname.equals(xsc)) return -1; if (rname.equals(xsc)) diff --git a/core/java/src/net/i2p/crypto/SHA1.java b/core/java/src/net/i2p/crypto/SHA1.java index 7ea68de562984c2581a946020ca0280aa0c81c11..bfe07630ca2bc97408efd9a15dc38b1dfa77f699 100644 --- a/core/java/src/net/i2p/crypto/SHA1.java +++ b/core/java/src/net/i2p/crypto/SHA1.java @@ -20,6 +20,8 @@ import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import net.i2p.util.SystemVersion; + /** * NOTE: As of 0.8.7, use getInstance() instead of new SHA1(), which will * return the JVM's MessageDigest if it is faster. @@ -94,10 +96,8 @@ public final class SHA1 extends MessageDigest implements Cloneable { static { // oddly, Bitzi is faster than Oracle - see test results below boolean useBitzi = true; - String vendor = System.getProperty("java.vendor"); - if (vendor.startsWith("Apache") || // Harmony - vendor.startsWith("GNU Classpath") || // JamVM - vendor.startsWith("Free Software Foundation")) { // gij + if (SystemVersion.isApache() || // Harmony + SystemVersion.isGNU()) { // JamVM or gij try { MessageDigest.getInstance("SHA-1"); useBitzi = false; diff --git a/core/java/src/net/i2p/util/ReusableGZIPInputStream.java b/core/java/src/net/i2p/util/ReusableGZIPInputStream.java index f09c9711c3e4c1c84bc984d42c5ecee0bf99bcae..5ef5b7801f88002a6bf2cb1edc705139bad7a34d 100644 --- a/core/java/src/net/i2p/util/ReusableGZIPInputStream.java +++ b/core/java/src/net/i2p/util/ReusableGZIPInputStream.java @@ -9,7 +9,7 @@ import java.util.concurrent.LinkedBlockingQueue; public class ReusableGZIPInputStream extends ResettableGZIPInputStream { // Apache Harmony 5.0M13 Deflater doesn't work after reset() // Neither does Android - private static final boolean ENABLE_CACHING = !(System.getProperty("java.vendor").startsWith("Apache") || + private static final boolean ENABLE_CACHING = !(SystemVersion.isApache() || SystemVersion.isAndroid()); private static final LinkedBlockingQueue<ReusableGZIPInputStream> _available; static { diff --git a/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java b/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java index fe686095e440e54556ff9dbcd7a44e76ee363f44..3cbf1dd3356c6d4fb30b8210ad097ddc3d33e318 100644 --- a/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java +++ b/core/java/src/net/i2p/util/ReusableGZIPOutputStream.java @@ -20,7 +20,7 @@ import net.i2p.data.DataHelper; public class ReusableGZIPOutputStream extends ResettableGZIPOutputStream { // Apache Harmony 5.0M13 Deflater doesn't work after reset() // Neither does Android - private static final boolean ENABLE_CACHING = !(System.getProperty("java.vendor").startsWith("Apache") || + private static final boolean ENABLE_CACHING = !(SystemVersion.isApache() || SystemVersion.isAndroid()); private static final LinkedBlockingQueue<ReusableGZIPOutputStream> _available; static { diff --git a/core/java/src/net/i2p/util/SystemVersion.java b/core/java/src/net/i2p/util/SystemVersion.java index d43cddc8987442b48ce84e520cf7f10c22fd2116..484a293238cba423364b390ce15c1197b46b94fd 100644 --- a/core/java/src/net/i2p/util/SystemVersion.java +++ b/core/java/src/net/i2p/util/SystemVersion.java @@ -15,14 +15,23 @@ public abstract class SystemVersion { private static final boolean _isWin = System.getProperty("os.name").startsWith("Win"); private static final boolean _isMac = System.getProperty("os.name").startsWith("Mac"); - private static final boolean _isAndroid = System.getProperty("java.vendor").contains("Android"); + private static final boolean _isAndroid; + private static final boolean _isApache; + private static final boolean _isGNU; private static final boolean _is64 = "64".equals(System.getProperty("sun.arch.data.model")) || System.getProperty("os.arch").contains("64"); + private static final boolean _hasWrapper = System.getProperty("wrapper.version") != null; private static final boolean _oneDotSix; private static final int _androidSDK; static { + String vendor = System.getProperty("java.vendor"); + _isAndroid = vendor.contains("Android"); + _isApache = vendor.startsWith("Apache"); + _isGNU = vendor.startsWith("GNU Classpath") || // JamVM + vendor.startsWith("Free Software Foundation"); // gij + int sdk = 0; if (_isAndroid) { try { @@ -52,6 +61,20 @@ public abstract class SystemVersion { return _isAndroid; } + /** + * Apache Harmony JVM, or Android + */ + public static boolean isApache() { + return _isApache || _isAndroid; + } + + /** + * gij or JamVM with GNU Classpath + */ + public static boolean isGNU() { + return _isGNU; + } + /** * Better than (new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0 * as it handles Android also, where java.version = "0". @@ -90,6 +113,6 @@ public abstract class SystemVersion { * Same as I2PAppContext.hasWrapper() */ public static boolean hasWrapper() { - return System.getProperty("wrapper.version") != null; + return _hasWrapper; } } diff --git a/history.txt b/history.txt index 191680e4ba596d755fd5c1620e482669fda889f1..e10156df615b40daa95c34dc1025927223ae969d 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,8 @@ +2012-10-14 zzz + * Console: Use non-nio connector for Java 5 and JamVM/gij + (tickets #715 and #743) + * i2psnark: Fix request tracking bug preventing piece requests + 2012-10-11 kytv * Italian translation updates from Transifex * i2prouter: diff --git a/installer/resources/eepsite/jetty.xml b/installer/resources/eepsite/jetty.xml index ba30a55ebd8264e540799807a8eeaf874ad8fb1d..0e873ca7709e5fea1d4818035b137562779d705a 100644 --- a/installer/resources/eepsite/jetty.xml +++ b/installer/resources/eepsite/jetty.xml @@ -90,7 +90,9 @@ <!-- Use this connector for many frequently idle connections and for threadless continuations. - Not recommended on Java 5 - comment out and uncomment the + Not recommended on Java 5 - comment this out, and uncomment the + SocketConnector below. + Do not use for gij or JamVM - comment this out, and uncomment the SocketConnector below. --> <Call name="addConnector"> diff --git a/installer/resources/i2prouter b/installer/resources/i2prouter index d49877795540071e606a033c16e2b7ed109a1846..fde3a0d4706dea92313a43f6b8d66417ef822940 100644 --- a/installer/resources/i2prouter +++ b/installer/resources/i2prouter @@ -45,7 +45,7 @@ GETTEXT=$(which gettext > /dev/null 2>&1) # Where to install the systemd service SYSTEMD_SERVICE="/etc/systemd/system/${APP_NAME}.service" -if grep -q systemd /proc/cmdline; then +if grep -q systemd /proc/1/comm ; then USE_SYSTEMD=1 fi @@ -1321,6 +1321,8 @@ installdaemon() { echo "esac" >> /etc/rc.d/${APP_NAME} chmod 755 /etc/rc.d/${APP_NAME} chown root:root /etc/rc.d/${APP_NAME} + eval echo `gettext ' The $APP_LONG_NAME daemon has been installed.'` + eval echo `gettext ' Add \"i2p\" to the DAEMONS variable in /etc/rc.conf to enable.'` else # We'll end up here if systemd is enabled. # If systemd is enabled we don't need the initscript @@ -1330,10 +1332,6 @@ installdaemon() { if [ ! -f "${SYSTEMD_SERVICE}" ]; then installsystemd fi - if ! grep -q systemd /proc/cmdline; then - eval echo `gettext ' The $APP_LONG_NAME daemon has been installed.'` - eval echo `gettext ' Add \"i2p\" to the DAEMONS variable in /etc/rc.conf to enable.'` - fi fi elif [ -f /etc/SuSE-release ] ; then eval echo `gettext 'Detected SuSE or SLES:'` diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 31c35f8c3e7f27dae7384d36e3443978e8ab5e40..ea17ad55f3270be34b24fd56bd0b1495da601896 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 14; + public final static long BUILD = 15; /** for example "-test" */ public final static String EXTRA = "";