forked from I2P_Developers/i2p.i2p
merge of '380c87670c1c931cf39e93d5600c4954c6e13d1e'
and '4fe47402bea065caae229256d58d87e60607602a'
This commit is contained in:
@@ -18,7 +18,7 @@ public class CoreVersion {
|
||||
/** deprecated */
|
||||
public final static String ID = "Monotone";
|
||||
|
||||
public final static String VERSION = "0.9.21";
|
||||
public final static String VERSION = "0.9.22";
|
||||
|
||||
/**
|
||||
* For Vuze.
|
||||
|
@@ -84,6 +84,7 @@ public class I2PAppContext {
|
||||
private RandomSource _random;
|
||||
private KeyGenerator _keyGenerator;
|
||||
protected KeyRing _keyRing; // overridden in RouterContext
|
||||
@SuppressWarnings("deprecation")
|
||||
private SimpleScheduler _simpleScheduler;
|
||||
private SimpleTimer _simpleTimer;
|
||||
private SimpleTimer2 _simpleTimer2;
|
||||
@@ -532,7 +533,7 @@ public class I2PAppContext {
|
||||
* @return set of Strings containing the names of defined system properties
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Set<String> getPropertyNames() {
|
||||
public Set<String> getPropertyNames() {
|
||||
// clone to avoid ConcurrentModificationException
|
||||
Set<String> names = new HashSet<String>((Set<String>) (Set) ((Properties) System.getProperties().clone()).keySet()); // TODO-Java6: s/keySet()/stringPropertyNames()/
|
||||
if (_overrideProps != null)
|
||||
@@ -940,6 +941,7 @@ public class I2PAppContext {
|
||||
* @since 0.9 to replace static instance in the class
|
||||
* @deprecated in 0.9.20, use simpleTimer2()
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public SimpleScheduler simpleScheduler() {
|
||||
if (!_simpleSchedulerInitialized)
|
||||
initializeSimpleScheduler();
|
||||
|
@@ -18,6 +18,7 @@ import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.PrivateKey;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.SessionTag;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
|
||||
/**
|
||||
@@ -98,7 +99,7 @@ public interface I2PSession {
|
||||
* objects that were sent along side the given keyUsed.
|
||||
* @return success
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
@@ -106,7 +107,7 @@ public interface I2PSession {
|
||||
* @param tagsSent UNUSED, IGNORED.
|
||||
* @return success
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* End-to-End Crypto is disabled, tags and keys are ignored.
|
||||
@@ -116,7 +117,7 @@ public interface I2PSession {
|
||||
* @return success
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire) throws I2PSessionException;
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* See I2PSessionMuxedImpl for proto/port details.
|
||||
@@ -133,7 +134,7 @@ public interface I2PSession {
|
||||
* @return success
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
|
||||
int proto, int fromPort, int toPort) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
@@ -152,7 +153,7 @@ public interface I2PSession {
|
||||
* @return success
|
||||
* @since 0.7.1
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
|
||||
int proto, int fromPort, int toPort) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
@@ -171,7 +172,7 @@ public interface I2PSession {
|
||||
* @return success
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
|
||||
int proto, int fromPort, int toPort, int flags) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
|
@@ -132,7 +132,7 @@ class I2CPMessageProducer {
|
||||
* @param newKey unused - no end-to-end crypto
|
||||
*/
|
||||
public void sendMessage(I2PSessionImpl session, Destination dest, long nonce, byte[] payload, SessionTag tag,
|
||||
SessionKey key, Set tags, SessionKey newKey, long expires) throws I2PSessionException {
|
||||
SessionKey key, Set<SessionTag> tags, SessionKey newKey, long expires) throws I2PSessionException {
|
||||
sendMessage(session, dest, nonce, payload, expires, 0);
|
||||
}
|
||||
|
||||
|
@@ -29,6 +29,7 @@ import net.i2p.client.SendMessageStatusListener;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.SessionTag;
|
||||
import net.i2p.data.i2cp.MessageId;
|
||||
import net.i2p.data.i2cp.MessageStatusMessage;
|
||||
import net.i2p.util.Log;
|
||||
@@ -210,17 +211,17 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
throw new UnsupportedOperationException("Use MuxedImpl");
|
||||
}
|
||||
/** @throws UnsupportedOperationException always, use MuxedImpl */
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
|
||||
int proto, int fromport, int toport) throws I2PSessionException {
|
||||
throw new UnsupportedOperationException("Use MuxedImpl");
|
||||
}
|
||||
/** @throws UnsupportedOperationException always, use MuxedImpl */
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
|
||||
int proto, int fromport, int toport) throws I2PSessionException {
|
||||
throw new UnsupportedOperationException("Use MuxedImpl");
|
||||
}
|
||||
/** @throws UnsupportedOperationException always, use MuxedImpl */
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expire,
|
||||
int proto, int fromport, int toport, int flags) throws I2PSessionException {
|
||||
throw new UnsupportedOperationException("Use MuxedImpl");
|
||||
}
|
||||
@@ -253,7 +254,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException {
|
||||
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set<SessionTag> tagsSent) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, 0, payload.length, keyUsed, tagsSent, 0);
|
||||
}
|
||||
|
||||
@@ -261,7 +262,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
* @param keyUsed unused - no end-to-end crypto
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent)
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent)
|
||||
throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0);
|
||||
}
|
||||
@@ -272,7 +273,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
* @param keyUsed unused - no end-to-end crypto
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires)
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent, long expires)
|
||||
throws I2PSessionException {
|
||||
if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message");
|
||||
synchronized (_stateLock) {
|
||||
@@ -339,7 +340,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
* @param keyUsed unused - no end-to-end crypto
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
|
||||
protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set<SessionTag> tagsSent, long expires)
|
||||
throws I2PSessionException {
|
||||
return sendBestEffort(dest, payload, expires, 0);
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ import net.i2p.client.SendMessageStatusListener;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.SessionKey;
|
||||
import net.i2p.data.SessionTag;
|
||||
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
@@ -163,7 +164,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
|
||||
SessionKey keyUsed, Set tagsSent, long expires)
|
||||
SessionKey keyUsed, Set<SessionTag> tagsSent, long expires)
|
||||
throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED);
|
||||
}
|
||||
@@ -173,7 +174,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
* @param tagsSent unused - no end-to-end crypto
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set<SessionTag> tagsSent,
|
||||
int proto, int fromport, int toport) throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromport, toport);
|
||||
}
|
||||
@@ -192,7 +193,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
|
||||
SessionKey keyUsed, Set tagsSent, long expires,
|
||||
SessionKey keyUsed, Set<SessionTag> tagsSent, long expires,
|
||||
int proto, int fromPort, int toPort)
|
||||
throws I2PSessionException {
|
||||
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromPort, toPort, 0);
|
||||
@@ -213,7 +214,7 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
*/
|
||||
@Override
|
||||
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
|
||||
SessionKey keyUsed, Set tagsSent, long expires,
|
||||
SessionKey keyUsed, Set<SessionTag> tagsSent, long expires,
|
||||
int proto, int fromPort, int toPort, int flags)
|
||||
throws I2PSessionException {
|
||||
payload = prepPayload(payload, offset, size, proto, fromPort, toPort);
|
||||
|
@@ -621,11 +621,33 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
////////// Start NamingService API
|
||||
|
||||
/*
|
||||
*
|
||||
* Will strip a "www." prefix and retry if lookup fails
|
||||
*
|
||||
* @param hostname upper/lower case ok
|
||||
* @param options If non-null and contains the key "list", lookup in
|
||||
* that list only, otherwise all lists
|
||||
*/
|
||||
@Override
|
||||
public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
|
||||
Destination rv = lookup2(hostname, lookupOptions, storedOptions);
|
||||
if (rv == null) {
|
||||
// if hostname starts with "www.", strip and try again
|
||||
// but not for www.i2p
|
||||
hostname = hostname.toLowerCase(Locale.US);
|
||||
if (hostname.startsWith("www.") && hostname.length() > 7) {
|
||||
hostname = hostname.substring(4);
|
||||
rv = lookup2(hostname, lookupOptions, storedOptions);
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* @param options If non-null and contains the key "list", lookup in
|
||||
* that list only, otherwise all lists
|
||||
*/
|
||||
private Destination lookup2(String hostname, Properties lookupOptions, Properties storedOptions) {
|
||||
String listname = null;
|
||||
if (lookupOptions != null)
|
||||
listname = lookupOptions.getProperty("list");
|
||||
|
@@ -41,8 +41,8 @@ public class MetaNamingService extends DummyNamingService {
|
||||
while (tok.hasMoreTokens()) {
|
||||
try {
|
||||
Class<?> cls = Class.forName(tok.nextToken());
|
||||
Constructor<?> con = cls.getConstructor(new Class[] { I2PAppContext.class });
|
||||
addNamingService((NamingService)con.newInstance(new Object[] { context }), false);
|
||||
Constructor<?> con = cls.getConstructor(I2PAppContext.class);
|
||||
addNamingService((NamingService)con.newInstance(), false);
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
|
@@ -536,8 +536,8 @@ public abstract class NamingService {
|
||||
String impl = context.getProperty(PROP_IMPL, DEFAULT_IMPL);
|
||||
try {
|
||||
Class<?> cls = Class.forName(impl);
|
||||
Constructor<?> con = cls.getConstructor(new Class[] { I2PAppContext.class });
|
||||
instance = (NamingService)con.newInstance(new Object[] { context });
|
||||
Constructor<?> con = cls.getConstructor(I2PAppContext.class);
|
||||
instance = (NamingService)con.newInstance(context);
|
||||
} catch (Exception ex) {
|
||||
Log log = context.logManager().getLog(NamingService.class);
|
||||
// Blockfile may throw RuntimeException but HostsTxt won't
|
||||
|
@@ -77,6 +77,8 @@ public class SingleFileNamingService extends NamingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Will strip a "www." prefix and retry if lookup fails
|
||||
*
|
||||
* @param hostname case-sensitive; caller should convert to lower case
|
||||
* @param lookupOptions ignored
|
||||
* @param storedOptions ignored
|
||||
@@ -85,6 +87,8 @@ public class SingleFileNamingService extends NamingService {
|
||||
public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
|
||||
try {
|
||||
String key = getKey(hostname);
|
||||
if (key == null && hostname.startsWith("www.") && hostname.length() > 7)
|
||||
key = getKey(hostname.substring(4));
|
||||
if (key != null)
|
||||
return lookupBase64(key);
|
||||
} catch (Exception ioe) {
|
||||
|
@@ -44,28 +44,7 @@ public class CryptixAESEngine extends AESEngine {
|
||||
|
||||
/** see test results below */
|
||||
private static final int MIN_SYSTEM_AES_LENGTH = 704;
|
||||
private static final boolean USE_SYSTEM_AES;
|
||||
static {
|
||||
boolean systemOK = false;
|
||||
if (hasAESNI()) {
|
||||
try {
|
||||
systemOK = Cipher.getMaxAllowedKeyLength("AES") >= 256;
|
||||
} catch (GeneralSecurityException gse) {
|
||||
// a NoSuchAlgorithmException
|
||||
} catch (NoSuchMethodError nsme) {
|
||||
// JamVM, gij
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
systemOK = true;
|
||||
} catch (GeneralSecurityException gse) {
|
||||
}
|
||||
}
|
||||
}
|
||||
USE_SYSTEM_AES = systemOK;
|
||||
//System.out.println("Using system AES? " + systemOK);
|
||||
}
|
||||
private static final boolean USE_SYSTEM_AES = hasAESNI() && CryptoCheck.isUnlimited();
|
||||
|
||||
/**
|
||||
* Do we have AES-NI support in the processor and JVM?
|
||||
|
47
core/java/src/net/i2p/crypto/CryptoCheck.java
Normal file
47
core/java/src/net/i2p/crypto/CryptoCheck.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Moved from CryptixAESEngine and net.i2p.router.tasks.CryptoChecker
|
||||
*
|
||||
* @since 0.9.23
|
||||
*/
|
||||
public class CryptoCheck {
|
||||
|
||||
private static final boolean _isUnlimited;
|
||||
|
||||
static {
|
||||
boolean unlimited = false;
|
||||
try {
|
||||
unlimited = Cipher.getMaxAllowedKeyLength("AES") >= 256;
|
||||
} catch (GeneralSecurityException gse) {
|
||||
// a NoSuchAlgorithmException
|
||||
} catch (NoSuchMethodError nsme) {
|
||||
// JamVM, gij
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
SecretKeySpec key = new SecretKeySpec(new byte[32], "AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, key);
|
||||
unlimited = true;
|
||||
} catch (GeneralSecurityException gse) {
|
||||
}
|
||||
}
|
||||
_isUnlimited = unlimited;
|
||||
}
|
||||
|
||||
private CryptoCheck() {}
|
||||
|
||||
/**
|
||||
* Do we have unlimited crypto?
|
||||
*/
|
||||
public static boolean isUnlimited() {
|
||||
return _isUnlimited;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("Unlimited? " + isUnlimited());
|
||||
}
|
||||
}
|
@@ -92,8 +92,8 @@ public class CryptoConstants {
|
||||
if (ECConstants.isBCAvailable()) {
|
||||
try {
|
||||
Class<?> cls = Class.forName("org.bouncycastle.jce.spec.ElGamalParameterSpec");
|
||||
Constructor<?> con = cls.getConstructor(new Class[] {BigInteger.class, BigInteger.class});
|
||||
spec = (AlgorithmParameterSpec)con.newInstance(new Object[] {elgp, elgg});
|
||||
Constructor<?> con = cls.getConstructor(BigInteger.class, BigInteger.class);
|
||||
spec = (AlgorithmParameterSpec)con.newInstance(elgp, elgg);
|
||||
//System.out.println("BC ElG spec loaded");
|
||||
} catch (Exception e) {
|
||||
//System.out.println("BC ElG spec failed");
|
||||
|
@@ -42,8 +42,8 @@ class ECConstants {
|
||||
if (Security.getProvider("BC") == null) {
|
||||
try {
|
||||
Class<?> cls = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
|
||||
Constructor<?> con = cls.getConstructor(new Class[0]);
|
||||
Provider bc = (Provider)con.newInstance(new Object[0]);
|
||||
Constructor<?> con = cls.getConstructor();
|
||||
Provider bc = (Provider)con.newInstance();
|
||||
Security.addProvider(bc);
|
||||
log("Added BC provider");
|
||||
loaded = true;
|
||||
|
@@ -501,6 +501,7 @@ public class KeyStoreUtil {
|
||||
l.log(level, msg, t);
|
||||
}
|
||||
|
||||
/****
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
if (args.length > 0) {
|
||||
@@ -521,4 +522,5 @@ public class KeyStoreUtil {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
****/
|
||||
}
|
||||
|
@@ -11,7 +11,9 @@ import java.util.Map;
|
||||
|
||||
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.SimpleDataStructure;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* Defines the properties for various signature types
|
||||
@@ -193,8 +195,24 @@ public enum SigType {
|
||||
return true;
|
||||
try {
|
||||
getParams();
|
||||
if (getBaseAlgorithm() != SigAlgo.EdDSA)
|
||||
Signature.getInstance(getAlgorithmName());
|
||||
if (getBaseAlgorithm() != SigAlgo.EdDSA) {
|
||||
Signature jsig = Signature.getInstance(getAlgorithmName());
|
||||
if (getBaseAlgorithm() == SigAlgo.EC && SystemVersion.isGentoo() ) {
|
||||
// Do a full keygen/sign test on Gentoo, because it lies. Keygen works but sigs fail.
|
||||
// https://bugs.gentoo.org/show_bug.cgi?id=528338
|
||||
// http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=2497
|
||||
// http://zzz.i2p/topics/1931
|
||||
// Be sure nothing in the code paths below calls isAvailable()
|
||||
// get an I2P keypair
|
||||
SimpleDataStructure[] keys = KeyGenerator.getInstance().generateSigningKeys(this);
|
||||
SigningPrivateKey privKey = (SigningPrivateKey) keys[1];
|
||||
// convert privkey back to Java key and sign
|
||||
jsig.initSign(SigUtil.toJavaECKey(privKey));
|
||||
// use the pubkey as random data
|
||||
jsig.update(keys[0].getData());
|
||||
jsig.sign();
|
||||
}
|
||||
}
|
||||
getDigestInstance();
|
||||
getHashInstance();
|
||||
} catch (Exception e) {
|
||||
|
@@ -16,7 +16,7 @@ import java.io.Serializable;
|
||||
* maps, and the like.
|
||||
*
|
||||
*/
|
||||
public class ByteArray implements Serializable, Comparable {
|
||||
public class ByteArray implements Serializable, Comparable<ByteArray> {
|
||||
private byte[] _data;
|
||||
private int _valid;
|
||||
private int _offset;
|
||||
@@ -85,9 +85,8 @@ public class ByteArray implements Serializable, Comparable {
|
||||
return (llen == rlen) && DataHelper.eq(lhs, loff, rhs, roff, llen);
|
||||
}
|
||||
|
||||
public final int compareTo(Object obj) {
|
||||
if (obj.getClass() != getClass()) throw new ClassCastException("invalid object: " + obj);
|
||||
return DataHelper.compareTo(_data, ((ByteArray)obj).getData());
|
||||
public final int compareTo(ByteArray ba) {
|
||||
return DataHelper.compareTo(_data, ba.getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -47,16 +47,17 @@ public class Certificate extends DataStructureImpl {
|
||||
public final static int CERTIFICATE_TYPE_KEY = 5;
|
||||
|
||||
/**
|
||||
* If null cert, return immutable static instance, else create new
|
||||
* If null, P256 key, or Ed25519 key cert, return immutable static instance, else create new
|
||||
* @throws DataFormatException if not enough bytes
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public static Certificate create(byte[] data, int off) throws DataFormatException {
|
||||
int type;
|
||||
byte[] payload;
|
||||
int length;
|
||||
try {
|
||||
type = data[off] & 0xff;
|
||||
int length = (int) DataHelper.fromLong(data, off + 1, 2);
|
||||
length = (int) DataHelper.fromLong(data, off + 1, 2);
|
||||
if (type == 0 && length == 0)
|
||||
return NULL_CERT;
|
||||
// from here down roughly the same as readBytes() below
|
||||
@@ -68,6 +69,12 @@ public class Certificate extends DataStructureImpl {
|
||||
throw new DataFormatException("not enough bytes", aioobe);
|
||||
}
|
||||
if (type == CERTIFICATE_TYPE_KEY) {
|
||||
if (length == 4) {
|
||||
if (Arrays.equals(payload, KeyCertificate.Ed25519_PAYLOAD))
|
||||
return KeyCertificate.ELG_Ed25519_CERT;
|
||||
if (Arrays.equals(payload, KeyCertificate.ECDSA256_PAYLOAD))
|
||||
return KeyCertificate.ELG_ECDSA256_CERT;
|
||||
}
|
||||
try {
|
||||
return new KeyCertificate(payload);
|
||||
} catch (DataFormatException dfe) {
|
||||
@@ -78,7 +85,7 @@ public class Certificate extends DataStructureImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* If null cert, return immutable static instance, else create new
|
||||
* If null, P256 key, or Ed25519 key cert, return immutable static instance, else create new
|
||||
* @since 0.8.3
|
||||
*/
|
||||
public static Certificate create(InputStream in) throws DataFormatException, IOException {
|
||||
@@ -93,8 +100,15 @@ public class Certificate extends DataStructureImpl {
|
||||
int read = DataHelper.read(in, payload);
|
||||
if (read != length)
|
||||
throw new DataFormatException("Not enough bytes for the payload (read: " + read + " length: " + length + ')');
|
||||
if (type == CERTIFICATE_TYPE_KEY)
|
||||
if (type == CERTIFICATE_TYPE_KEY) {
|
||||
if (length == 4) {
|
||||
if (Arrays.equals(payload, KeyCertificate.Ed25519_PAYLOAD))
|
||||
return KeyCertificate.ELG_Ed25519_CERT;
|
||||
if (Arrays.equals(payload, KeyCertificate.ECDSA256_PAYLOAD))
|
||||
return KeyCertificate.ELG_ECDSA256_CERT;
|
||||
}
|
||||
return new KeyCertificate(payload);
|
||||
}
|
||||
return new Certificate(type, payload);
|
||||
}
|
||||
|
||||
|
@@ -1546,7 +1546,7 @@ public class DataHelper {
|
||||
// years
|
||||
t = ngettext("1 year", "{0} years", (int) (ms / (365L * 24 * 60 * 60 * 1000)));
|
||||
} else {
|
||||
return _("n/a");
|
||||
return _t("n/a");
|
||||
}
|
||||
// Replace minus sign to work around
|
||||
// bug in Chrome (and IE?), line breaks at the minus sign
|
||||
@@ -1593,7 +1593,7 @@ public class DataHelper {
|
||||
// years
|
||||
t = ngettext("1 year", "{0} years", (int) (ms / (365L * 24 * 60 * 60 * 1000)));
|
||||
} else {
|
||||
return _("n/a");
|
||||
return _t("n/a");
|
||||
}
|
||||
if (ms < 0)
|
||||
t = t.replace("-", "−");
|
||||
@@ -1602,7 +1602,7 @@ public class DataHelper {
|
||||
|
||||
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
|
||||
|
||||
private static String _(String key) {
|
||||
private static String _t(String key) {
|
||||
return Translate.getString(key, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
|
||||
}
|
||||
|
||||
|
@@ -17,15 +17,41 @@ public class KeyCertificate extends Certificate {
|
||||
|
||||
public static final int HEADER_LENGTH = 4;
|
||||
|
||||
/** @since 0.9.22 pkg private for Certificate.create() */
|
||||
static final byte[] Ed25519_PAYLOAD = new byte[] {
|
||||
0, (byte) (SigType.EdDSA_SHA512_Ed25519.getCode()), 0, 0
|
||||
};
|
||||
|
||||
/** @since 0.9.22 pkg private for Certificate.create() */
|
||||
static final byte[] ECDSA256_PAYLOAD = new byte[] {
|
||||
0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
|
||||
};
|
||||
|
||||
/**
|
||||
* An immutable ElG/ECDSA-P256 certificate.
|
||||
*/
|
||||
public static final KeyCertificate ELG_ECDSA256_CERT;
|
||||
|
||||
/**
|
||||
* An immutable ElG/Ed25519 certificate.
|
||||
* @since 0.9.22
|
||||
*/
|
||||
public static final KeyCertificate ELG_Ed25519_CERT;
|
||||
|
||||
static {
|
||||
KeyCertificate kc;
|
||||
try {
|
||||
kc = new ECDSA256Cert();
|
||||
} catch (DataFormatException dfe) {
|
||||
kc = null; // won't happen
|
||||
throw new RuntimeException(dfe); // won't happen
|
||||
}
|
||||
ELG_ECDSA256_CERT = kc;
|
||||
try {
|
||||
kc = new Ed25519Cert();
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new RuntimeException(dfe); // won't happen
|
||||
}
|
||||
ELG_Ed25519_CERT = kc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,19 +211,17 @@ public class KeyCertificate extends Certificate {
|
||||
|
||||
/**
|
||||
* An immutable ElG/ECDSA-256 certificate.
|
||||
* @since 0.8.3
|
||||
*/
|
||||
private static final class ECDSA256Cert extends KeyCertificate {
|
||||
private static final byte[] ECDSA256_DATA = new byte[] {
|
||||
CERTIFICATE_TYPE_KEY, 0, HEADER_LENGTH, 0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
|
||||
};
|
||||
private static final int ECDSA256_LENGTH = ECDSA256_DATA.length;
|
||||
private static final byte[] ECDSA256_PAYLOAD = new byte[] {
|
||||
0, (byte) (SigType.ECDSA_SHA256_P256.getCode()), 0, 0
|
||||
};
|
||||
private final int _hashcode;
|
||||
|
||||
public ECDSA256Cert() throws DataFormatException {
|
||||
super(ECDSA256_PAYLOAD);
|
||||
_hashcode = super.hashCode();
|
||||
}
|
||||
|
||||
/** @throws RuntimeException always */
|
||||
@@ -246,7 +270,75 @@ public class KeyCertificate extends Certificate {
|
||||
/** Overridden for efficiency */
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1234567;
|
||||
return _hashcode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An immutable ElG/Ed25519 certificate.
|
||||
* @since 0.9.22
|
||||
*/
|
||||
private static final class Ed25519Cert extends KeyCertificate {
|
||||
private static final byte[] ED_DATA = new byte[] { CERTIFICATE_TYPE_KEY,
|
||||
0, HEADER_LENGTH,
|
||||
0, (byte) SigType.EdDSA_SHA512_Ed25519.getCode(),
|
||||
0, 0
|
||||
};
|
||||
private static final int ED_LENGTH = ED_DATA.length;
|
||||
private final int _hashcode;
|
||||
|
||||
public Ed25519Cert() throws DataFormatException {
|
||||
super(Ed25519_PAYLOAD);
|
||||
_hashcode = super.hashCode();
|
||||
}
|
||||
|
||||
/** @throws RuntimeException always */
|
||||
@Override
|
||||
public void setCertificateType(int type) {
|
||||
throw new RuntimeException("Data already set");
|
||||
}
|
||||
|
||||
/** @throws RuntimeException always */
|
||||
@Override
|
||||
public void setPayload(byte[] payload) {
|
||||
throw new RuntimeException("Data already set");
|
||||
}
|
||||
|
||||
/** @throws RuntimeException always */
|
||||
@Override
|
||||
public void readBytes(InputStream in) throws DataFormatException, IOException {
|
||||
throw new RuntimeException("Data already set");
|
||||
}
|
||||
|
||||
/** Overridden for efficiency */
|
||||
@Override
|
||||
public void writeBytes(OutputStream out) throws IOException {
|
||||
out.write(ED_DATA);
|
||||
}
|
||||
|
||||
/** Overridden for efficiency */
|
||||
@Override
|
||||
public int writeBytes(byte target[], int offset) {
|
||||
System.arraycopy(ED_DATA, 0, target, offset, ED_LENGTH);
|
||||
return ED_LENGTH;
|
||||
}
|
||||
|
||||
/** @throws RuntimeException always */
|
||||
@Override
|
||||
public int readBytes(byte source[], int offset) throws DataFormatException {
|
||||
throw new RuntimeException("Data already set");
|
||||
}
|
||||
|
||||
/** Overridden for efficiency */
|
||||
@Override
|
||||
public int size() {
|
||||
return ED_LENGTH;
|
||||
}
|
||||
|
||||
/** Overridden for efficiency */
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return _hashcode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -46,7 +46,6 @@ import net.i2p.util.SystemVersion;
|
||||
public class SDSCache<V extends SimpleDataStructure> {
|
||||
//private static final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(SDSCache.class);
|
||||
|
||||
private static final Class[] conArg = new Class[] { byte[].class };
|
||||
private static final double MIN_FACTOR = 0.20;
|
||||
private static final double MAX_FACTOR = 5.0;
|
||||
private static final double FACTOR;
|
||||
@@ -74,7 +73,7 @@ public class SDSCache<V extends SimpleDataStructure> {
|
||||
_cache = new LHMCache<Integer, WeakReference<V>>(size);
|
||||
_datalen = len;
|
||||
try {
|
||||
_rvCon = rvClass.getConstructor(conArg);
|
||||
_rvCon = rvClass.getConstructor(byte[].class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("SDSCache init error", e);
|
||||
}
|
||||
|
@@ -628,6 +628,7 @@ public class KBucketSet<T extends SimpleDataStructure> {
|
||||
* @param data size <= SDS length, else throws IAE
|
||||
* Can be 1 bigger if top byte is zero
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private T makeKey(byte[] data) {
|
||||
int len = _us.length();
|
||||
int dlen = data.length;
|
||||
|
@@ -15,6 +15,8 @@ import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
/**
|
||||
@@ -229,10 +231,10 @@ public abstract class Addresses {
|
||||
I2PAppContext ctx = I2PAppContext.getCurrentContext();
|
||||
if (ctx != null && ctx.isRouterContext()) {
|
||||
long maxMemory = SystemVersion.getMaxMemory();
|
||||
long min = 128;
|
||||
long min = 256;
|
||||
long max = 4096;
|
||||
// 512 nominal for 128 MB
|
||||
size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (256*1024))));
|
||||
// 1024 nominal for 128 MB
|
||||
size = (int) Math.max(min, Math.min(max, 1 + (maxMemory / (128*1024))));
|
||||
} else {
|
||||
size = 32;
|
||||
}
|
||||
@@ -260,12 +262,9 @@ public abstract class Addresses {
|
||||
}
|
||||
if (rv == null) {
|
||||
try {
|
||||
boolean isIPv4 = host.replaceAll("[0-9\\.]", "").length() == 0;
|
||||
if (isIPv4 && host.replaceAll("[0-9]", "").length() != 3)
|
||||
return null;
|
||||
rv = InetAddress.getByName(host).getAddress();
|
||||
if (isIPv4 ||
|
||||
host.replaceAll("[0-9a-fA-F:]", "").length() == 0) {
|
||||
if (InetAddressUtils.isIPv4Address(host) ||
|
||||
InetAddressUtils.isIPv6Address(host)) {
|
||||
synchronized (_IPAddress) {
|
||||
_IPAddress.put(host, rv);
|
||||
}
|
||||
|
@@ -24,6 +24,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import gnu.getopt.Getopt;
|
||||
|
||||
@@ -312,22 +314,52 @@ public class EepGet {
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse URL for a viable filename.
|
||||
*
|
||||
* @param url a URL giving the location of an online resource
|
||||
* @return a filename to save the resource as on local filesystem
|
||||
*/
|
||||
public static String suggestName(String url) {
|
||||
int last = url.lastIndexOf('/');
|
||||
if ((last < 0) || (url.lastIndexOf('#') > last))
|
||||
last = url.lastIndexOf('#');
|
||||
if ((last < 0) || (url.lastIndexOf('?') > last))
|
||||
last = url.lastIndexOf('?');
|
||||
if ((last < 0) || (url.lastIndexOf('=') > last))
|
||||
last = url.lastIndexOf('=');
|
||||
URL nameURL = null; // URL object
|
||||
String name; // suggested name
|
||||
|
||||
String name = null;
|
||||
if (last >= 0)
|
||||
name = sanitize(url.substring(last+1));
|
||||
if ( (name != null) && (name.length() > 0) )
|
||||
return name;
|
||||
else
|
||||
return sanitize(url);
|
||||
try {
|
||||
nameURL = new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
System.err.println("Please enter a properly formed URL.");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
String path = nameURL.getPath(); // discard any URI queries
|
||||
|
||||
// if no file specified, eepget scrapes webpage - use domain as name
|
||||
Pattern slashes = Pattern.compile("/+");
|
||||
Matcher matcher = slashes.matcher(path);
|
||||
// if empty path or just /'s - nameURL lets multiple /'s through
|
||||
if (path.equals("") || matcher.matches()) {
|
||||
name = sanitize(nameURL.getAuthority());
|
||||
// if path specified
|
||||
} else {
|
||||
int last = path.lastIndexOf('/');
|
||||
// if last / not at end of string, use following string as filename
|
||||
if (last != path.length() - 1) {
|
||||
name = sanitize(path.substring(last + 1));
|
||||
// if there's a trailing / group look for previous / as trim point
|
||||
} else {
|
||||
int i = 1;
|
||||
int slash;
|
||||
while (true) {
|
||||
slash = path.lastIndexOf('/', last - i);
|
||||
if (slash != last - i) {
|
||||
break;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
name = sanitize(path.substring(slash + 1, path.length() - i));
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
@@ -755,6 +787,8 @@ public class EepGet {
|
||||
Thread pusher = null;
|
||||
_decompressException = null;
|
||||
if (_isGzippedResponse) {
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Gzipped response, starting decompressor");
|
||||
PipedInputStream pi = BigPipedInputStream.getInstance();
|
||||
PipedOutputStream po = new PipedOutputStream(pi);
|
||||
pusher = new I2PAppThread(new Gunzipper(pi, _out), "EepGet Decompressor");
|
||||
@@ -1096,7 +1130,7 @@ public class EepGet {
|
||||
*/
|
||||
private int handleStatus(String line) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Status line: [" + line + "]");
|
||||
_log.debug("Status line: [" + line.trim() + "]");
|
||||
String[] toks = line.split(" ", 3);
|
||||
if (toks.length < 2) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
@@ -1160,17 +1194,13 @@ public class EepGet {
|
||||
lookahead[1] = lookahead[2];
|
||||
lookahead[2] = (byte)cur;
|
||||
}
|
||||
|
||||
private static boolean isEndOfHeaders(byte lookahead[]) {
|
||||
byte first = lookahead[0];
|
||||
byte second = lookahead[1];
|
||||
byte third = lookahead[2];
|
||||
return (isNL(second) && isNL(third)) || // \n\n
|
||||
(isNL(first) && isNL(third)); // \n\r\n
|
||||
return lookahead[2] == NL &&
|
||||
(lookahead[0] == NL || lookahead[1] == NL); // \n\n or \n\r\n
|
||||
}
|
||||
|
||||
/** we ignore any potential \r, since we trim it on write anyway */
|
||||
private static final byte NL = '\n';
|
||||
private static boolean isNL(byte b) { return (b == NL); }
|
||||
|
||||
/**
|
||||
* @param timeout may be null
|
||||
@@ -1315,7 +1345,8 @@ public class EepGet {
|
||||
buf.append("Content-length: ").append(_postData.length()).append("\r\n");
|
||||
// This will be replaced if we are going through I2PTunnelHTTPClient
|
||||
buf.append("Accept-Encoding: ");
|
||||
if ((!_shouldProxy) &&
|
||||
// as of 0.9.23, the proxy passes the Accept-Encoding header through
|
||||
if ( /* (!_shouldProxy) && */
|
||||
// This is kindof a hack, but if we are downloading a gzip file
|
||||
// we don't want to transparently gunzip it and save it as a .gz file.
|
||||
(!path.endsWith(".gz")) && (!path.endsWith(".tgz")))
|
||||
|
@@ -300,9 +300,9 @@ public class FileUtil {
|
||||
if (!_failedOracle) {
|
||||
try {
|
||||
Class<?> p200 = Class.forName("java.util.jar.Pack200", true, ClassLoader.getSystemClassLoader());
|
||||
Method newUnpacker = p200.getMethod("newUnpacker", (Class[]) null);
|
||||
Method newUnpacker = p200.getMethod("newUnpacker");
|
||||
Object unpacker = newUnpacker.invoke(null,(Object[]) null);
|
||||
Method unpack = unpacker.getClass().getMethod("unpack", new Class[] {InputStream.class, JarOutputStream.class});
|
||||
Method unpack = unpacker.getClass().getMethod("unpack", InputStream.class, JarOutputStream.class);
|
||||
// throws IOException
|
||||
unpack.invoke(unpacker, new Object[] {in, out});
|
||||
return;
|
||||
@@ -321,9 +321,9 @@ public class FileUtil {
|
||||
if (!_failedApache) {
|
||||
try {
|
||||
Class<?> p200 = Class.forName("org.apache.harmony.unpack200.Archive", true, ClassLoader.getSystemClassLoader());
|
||||
Constructor<?> newUnpacker = p200.getConstructor(new Class[] {InputStream.class, JarOutputStream.class});
|
||||
Object unpacker = newUnpacker.newInstance(new Object[] {in, out});
|
||||
Method unpack = unpacker.getClass().getMethod("unpack", (Class[]) null);
|
||||
Constructor<?> newUnpacker = p200.getConstructor(InputStream.class, JarOutputStream.class);
|
||||
Object unpacker = newUnpacker.newInstance(in, out);
|
||||
Method unpack = unpacker.getClass().getMethod("unpack");
|
||||
// throws IOException or Pack200Exception
|
||||
unpack.invoke(unpacker, (Object[]) null);
|
||||
return;
|
||||
|
@@ -14,10 +14,13 @@ import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Like I2PThread but with per-thread OOM listeners,
|
||||
* Like {@link I2PThread} but with per-thread OOM listeners,
|
||||
* rather than a static router-wide listener list,
|
||||
* so that an OOM in an app won't call the router listener
|
||||
* to shutdown the whole router.
|
||||
*
|
||||
* This is preferred for application use.
|
||||
* See {@link I2PThread} for features.
|
||||
*/
|
||||
public class I2PAppThread extends I2PThread {
|
||||
|
||||
@@ -38,9 +41,17 @@ public class I2PAppThread extends I2PThread {
|
||||
public I2PAppThread(Runnable r, String name) {
|
||||
super(r, name);
|
||||
}
|
||||
|
||||
public I2PAppThread(Runnable r, String name, boolean isDaemon) {
|
||||
super(r, name, isDaemon);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.23
|
||||
*/
|
||||
public I2PAppThread(ThreadGroup group, Runnable r, String name) {
|
||||
super(group, r, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fireOOM(OutOfMemoryError oom) {
|
||||
|
@@ -204,7 +204,15 @@ public class I2PSSLSocketFactory {
|
||||
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"
|
||||
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
|
||||
// following is disabled because it is weak
|
||||
// see e.g. https://bugzilla.mozilla.org/show_bug.cgi?id=1107787
|
||||
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA"
|
||||
// ??? "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"
|
||||
//
|
||||
// NOTE:
|
||||
// If you add anything here, please also add to installer/resources/eepsite/jetty-ssl.xml
|
||||
//
|
||||
}));
|
||||
|
||||
/**
|
||||
|
@@ -14,76 +14,63 @@ import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* In case its useful later...
|
||||
* (e.g. w/ native programatic thread dumping, etc)
|
||||
*
|
||||
* As of 0.9.21, I2PThreads are initialized to NORM_PRIORITY
|
||||
* (not the priority of the creating thread).
|
||||
* Preferred over {@link Thread} for all router uses.
|
||||
* For applications, {@link I2PAppThread} is preferred.
|
||||
* <p>
|
||||
* Provides the following features:
|
||||
* <ul>
|
||||
* <li>Logging to wrapper log on unexpected termination in {@link #run()}.
|
||||
* <li>Notification of OOM to registered listener (the router),
|
||||
* which will cause logging to the wrapper log and a router restart
|
||||
* <li>Catching and logging "OOM" caused by thread limit in {@link #start()}
|
||||
* with distinct message, and does not call the OOM listener.
|
||||
* <li>As of 0.9.21, initialization to NORM_PRIORITY
|
||||
* (not the priority of the creating thread).
|
||||
* </ul>
|
||||
*/
|
||||
public class I2PThread extends Thread {
|
||||
/**
|
||||
* Non-static to avoid refs to old context in Android.
|
||||
* Probably should just remove all the logging though.
|
||||
* Logging removed, too much trouble with extra contexts
|
||||
*/
|
||||
//private volatile Log _log;
|
||||
|
||||
private static final Set<OOMEventListener> _listeners = new CopyOnWriteArraySet<OOMEventListener>();
|
||||
//private String _name;
|
||||
//private Exception _createdBy;
|
||||
|
||||
public I2PThread() {
|
||||
super();
|
||||
setPriority(NORM_PRIORITY);
|
||||
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
|
||||
// _createdBy = new Exception("Created by");
|
||||
}
|
||||
|
||||
public I2PThread(String name) {
|
||||
super(name);
|
||||
setPriority(NORM_PRIORITY);
|
||||
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
|
||||
// _createdBy = new Exception("Created by");
|
||||
}
|
||||
|
||||
public I2PThread(Runnable r) {
|
||||
super(r);
|
||||
setPriority(NORM_PRIORITY);
|
||||
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
|
||||
// _createdBy = new Exception("Created by");
|
||||
}
|
||||
|
||||
public I2PThread(Runnable r, String name) {
|
||||
super(r, name);
|
||||
setPriority(NORM_PRIORITY);
|
||||
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
|
||||
// _createdBy = new Exception("Created by");
|
||||
}
|
||||
|
||||
public I2PThread(Runnable r, String name, boolean isDaemon) {
|
||||
super(r, name);
|
||||
setDaemon(isDaemon);
|
||||
setPriority(NORM_PRIORITY);
|
||||
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
|
||||
// _createdBy = new Exception("Created by");
|
||||
}
|
||||
|
||||
public I2PThread(ThreadGroup g, Runnable r) {
|
||||
super(g, r);
|
||||
setPriority(NORM_PRIORITY);
|
||||
//if ( (_log == null) || (_log.shouldLog(Log.DEBUG)) )
|
||||
// _createdBy = new Exception("Created by");
|
||||
}
|
||||
|
||||
/****
|
||||
private void log(int level, String msg) { log(level, msg, null); }
|
||||
|
||||
private void log(int level, String msg, Throwable t) {
|
||||
// we cant assume log is created
|
||||
if (_log == null) _log = new Log(I2PThread.class);
|
||||
if (_log.shouldLog(level))
|
||||
_log.log(level, msg, t);
|
||||
/**
|
||||
* @since 0.9.23
|
||||
*/
|
||||
public I2PThread(ThreadGroup group, Runnable r, String name) {
|
||||
super(group, r, name);
|
||||
setPriority(NORM_PRIORITY);
|
||||
}
|
||||
****/
|
||||
|
||||
|
||||
/**
|
||||
* Overridden to provide useful info to users on OOM, and to prevent
|
||||
* shutting down the whole JVM for what is most likely not a heap issue.
|
||||
@@ -109,19 +96,9 @@ public class I2PThread extends Thread {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
//_name = Thread.currentThread().getName();
|
||||
//log(Log.INFO, "New thread started" + (isDaemon() ? " (daemon): " : ": ") + _name, _createdBy);
|
||||
try {
|
||||
super.run();
|
||||
} catch (Throwable t) {
|
||||
/****
|
||||
try {
|
||||
log(Log.CRIT, "Thread terminated unexpectedly: " + getName(), t);
|
||||
} catch (Throwable woof) {
|
||||
System.err.println("Died within the OOM itself");
|
||||
t.printStackTrace();
|
||||
}
|
||||
****/
|
||||
if (t instanceof OutOfMemoryError) {
|
||||
fireOOM((OutOfMemoryError)t);
|
||||
} else {
|
||||
@@ -129,18 +106,8 @@ public class I2PThread extends Thread {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
// This creates a new I2PAppContext after it was deleted
|
||||
// in Router.finalShutdown() via RouterContext.killGlobalContext()
|
||||
//log(Log.INFO, "Thread finished normally: " + _name);
|
||||
}
|
||||
|
||||
/****
|
||||
protected void finalize() throws Throwable {
|
||||
//log(Log.DEBUG, "Thread finalized: " + _name);
|
||||
super.finalize();
|
||||
}
|
||||
****/
|
||||
|
||||
protected void fireOOM(OutOfMemoryError oom) {
|
||||
for (OOMEventListener listener : _listeners)
|
||||
listener.outOfMemory(oom);
|
||||
|
@@ -763,7 +763,7 @@ public class LogManager implements Flushable {
|
||||
|
||||
private static final AtomicInteger __id = new AtomicInteger();
|
||||
|
||||
private class ShutdownHook extends Thread {
|
||||
private class ShutdownHook extends I2PAppThread {
|
||||
private final int _id;
|
||||
public ShutdownHook() {
|
||||
_id = __id.incrementAndGet();
|
||||
|
@@ -67,10 +67,12 @@ abstract class LogWriterBase implements Runnable {
|
||||
|
||||
public void run() {
|
||||
_write = true;
|
||||
// don't bother on Android
|
||||
final boolean shouldReadConfig = !SystemVersion.isAndroid();
|
||||
try {
|
||||
while (_write) {
|
||||
flushRecords();
|
||||
if (_write)
|
||||
if (_write && shouldReadConfig)
|
||||
rereadConfig();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -145,7 +147,7 @@ abstract class LogWriterBase implements Runnable {
|
||||
private String dupMessage(int dupCount, LogRecord lastRecord, boolean reverse) {
|
||||
String arrows = reverse ? "↓↓↓" : "^^^";
|
||||
return LogRecordFormatter.getWhen(_manager, lastRecord) + ' ' + arrows + ' ' +
|
||||
_(dupCount, "1 similar message omitted", "{0} similar messages omitted") + ' ' + arrows + '\n';
|
||||
_t(dupCount, "1 similar message omitted", "{0} similar messages omitted") + ' ' + arrows + '\n';
|
||||
}
|
||||
|
||||
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
|
||||
@@ -154,7 +156,7 @@ abstract class LogWriterBase implements Runnable {
|
||||
* gettext
|
||||
* @since 0.9.3
|
||||
*/
|
||||
private String _(int a, String b, String c) {
|
||||
private String _t(int a, String b, String c) {
|
||||
return Translate.getString(a, b, c, _manager.getContext(), BUNDLE_NAME);
|
||||
}
|
||||
|
||||
|
@@ -33,6 +33,8 @@ public class PortMapper {
|
||||
public static final String SVC_BOB = "BOB";
|
||||
/** not necessary, already in config? */
|
||||
public static final String SVC_I2CP = "I2CP";
|
||||
/** @since 0.9.23 */
|
||||
public static final String SVC_I2CP_SSL = "I2CP-SSL";
|
||||
|
||||
/**
|
||||
* @param context unused for now
|
||||
@@ -109,7 +111,7 @@ public class PortMapper {
|
||||
* @since 0.9.20
|
||||
*/
|
||||
public void renderStatusHTML(Writer out) throws IOException {
|
||||
List<String> services = new ArrayList(_dir.keySet());
|
||||
List<String> services = new ArrayList<String>(_dir.keySet());
|
||||
out.write("<h2>Port Mapper</h2><table><tr><th>Service<th>Host<th>Port\n");
|
||||
Collections.sort(services);
|
||||
for (String s : services) {
|
||||
|
@@ -51,7 +51,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private class CommandThread extends Thread {
|
||||
private class CommandThread extends I2PAppThread {
|
||||
private final boolean consumeOutput;
|
||||
private final Object shellCommand;
|
||||
private final Result result;
|
||||
@@ -84,7 +84,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private static class StreamConsumer extends Thread {
|
||||
private static class StreamConsumer extends I2PAppThread {
|
||||
private final BufferedReader bufferedReader;
|
||||
|
||||
public StreamConsumer(InputStream inputStream) {
|
||||
@@ -115,7 +115,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private static class StreamReader extends Thread {
|
||||
private static class StreamReader extends I2PAppThread {
|
||||
private final BufferedReader bufferedReader;
|
||||
|
||||
public StreamReader(InputStream inputStream) {
|
||||
@@ -149,7 +149,7 @@ public class ShellCommand {
|
||||
*
|
||||
* @author hypercubus
|
||||
*/
|
||||
private static class StreamWriter extends Thread {
|
||||
private static class StreamWriter extends I2PAppThread {
|
||||
private final BufferedWriter bufferedWriter;
|
||||
|
||||
public StreamWriter(OutputStream outputStream) {
|
||||
|
@@ -6,6 +6,7 @@ import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
@@ -38,7 +39,7 @@ public class SimpleTimer2 {
|
||||
private static final int MAX_THREADS = 4;
|
||||
private final ScheduledThreadPoolExecutor _executor;
|
||||
private final String _name;
|
||||
private volatile int _count;
|
||||
private final AtomicInteger _count = new AtomicInteger();
|
||||
private final int _threads;
|
||||
|
||||
/**
|
||||
@@ -102,7 +103,7 @@ public class SimpleTimer2 {
|
||||
super.afterExecute(r, t);
|
||||
if (t != null) { // shoudn't happen, caught in RunnableEvent.run()
|
||||
Log log = I2PAppContext.getGlobalContext().logManager().getLog(SimpleTimer2.class);
|
||||
log.log(Log.CRIT, "wtf, event borked: " + r, t);
|
||||
log.log(Log.CRIT, "event borked: " + r, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,18 +111,19 @@ public class SimpleTimer2 {
|
||||
private class CustomThreadFactory implements ThreadFactory {
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread rv = Executors.defaultThreadFactory().newThread(r);
|
||||
rv.setName(_name + ' ' + (++_count) + '/' + _threads);
|
||||
rv.setName(_name + ' ' + _count.incrementAndGet() + '/' + _threads);
|
||||
// Uncomment this to test threadgrouping, but we should be all safe now that the constructor preallocates!
|
||||
// String name = rv.getThreadGroup().getName();
|
||||
// if(!name.equals("main")) {
|
||||
// (new Exception("OWCH! DAMN! Wrong ThreadGroup `" + name +"', `" + rv.getName() + "'")).printStackTrace();
|
||||
// }
|
||||
rv.setDaemon(true);
|
||||
rv.setPriority(Thread.NORM_PRIORITY + 1);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
private ScheduledFuture schedule(TimedEvent t, long timeoutMs) {
|
||||
private ScheduledFuture<?> schedule(TimedEvent t, long timeoutMs) {
|
||||
return _executor.schedule(t, timeoutMs, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@@ -164,7 +166,8 @@ public class SimpleTimer2 {
|
||||
* New code should use SimpleTimer2.TimedEvent.
|
||||
*
|
||||
* @since 0.9.20
|
||||
* @param timeoutMs run first and subsequent iterations of this event every timeoutMs ms
|
||||
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms, 5000 minimum
|
||||
* @throws IllegalArgumentException if timeoutMs less than 5000
|
||||
*/
|
||||
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long timeoutMs) {
|
||||
addPeriodicEvent(event, timeoutMs, timeoutMs);
|
||||
@@ -183,7 +186,8 @@ public class SimpleTimer2 {
|
||||
*
|
||||
* @since 0.9.20
|
||||
* @param delay run the first iteration of this event after delay ms
|
||||
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
|
||||
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms, 5000 minimum
|
||||
* @throws IllegalArgumentException if timeoutMs less than 5000
|
||||
*/
|
||||
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long delay, final long timeoutMs) {
|
||||
|
||||
@@ -245,7 +249,7 @@ public class SimpleTimer2 {
|
||||
private final SimpleTimer2 _pool;
|
||||
private int _fuzz;
|
||||
protected static final int DEFAULT_FUZZ = 3;
|
||||
private ScheduledFuture _future; // _executor.remove() doesn't work so we have to use this
|
||||
private ScheduledFuture<?> _future; // _executor.remove() doesn't work so we have to use this
|
||||
// ... and I expect cancelling this way is more efficient
|
||||
|
||||
/** state of the current event. All access should be under lock. */
|
||||
@@ -254,6 +258,8 @@ public class SimpleTimer2 {
|
||||
private long _nextRun;
|
||||
/** whether this was scheduled during RUNNING state. LOCKING: this */
|
||||
private boolean _rescheduleAfterRun;
|
||||
/** whether this was cancelled during RUNNING state. LOCKING: this */
|
||||
private boolean _cancelAfterRun;
|
||||
|
||||
/** must call schedule() later */
|
||||
public TimedEvent(SimpleTimer2 pool) {
|
||||
@@ -286,12 +292,17 @@ public class SimpleTimer2 {
|
||||
public synchronized void schedule(long timeoutMs) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Scheduling: " + this + " timeout = " + timeoutMs + " state: " + _state);
|
||||
if (timeoutMs <= 0 && _log.shouldLog(Log.WARN))
|
||||
if (timeoutMs <= 0) {
|
||||
// streaming timers do call with timeoutMs == 0
|
||||
if (timeoutMs < 0 && _log.shouldLog(Log.WARN))
|
||||
_log.warn("Timeout <= 0: " + this + " timeout = " + timeoutMs + " state: " + _state);
|
||||
timeoutMs = 1; // otherwise we may execute before _future is updated, which is fine
|
||||
// except it triggers 'early execution' warning logging
|
||||
}
|
||||
|
||||
// always set absolute time of execution
|
||||
_nextRun = timeoutMs + System.currentTimeMillis();
|
||||
_cancelAfterRun = false;
|
||||
|
||||
switch(_state) {
|
||||
case RUNNING:
|
||||
@@ -352,11 +363,13 @@ public class SimpleTimer2 {
|
||||
* @param timeoutMs
|
||||
*/
|
||||
public synchronized void forceReschedule(long timeoutMs) {
|
||||
cancel();
|
||||
// don't cancel while running!
|
||||
if (_state == TimedEventState.SCHEDULED)
|
||||
cancel();
|
||||
schedule(timeoutMs);
|
||||
}
|
||||
|
||||
/** returns true if cancelled */
|
||||
/** @return true if cancelled */
|
||||
public synchronized boolean cancel() {
|
||||
// always clear
|
||||
_rescheduleAfterRun = false;
|
||||
@@ -365,7 +378,9 @@ public class SimpleTimer2 {
|
||||
case CANCELLED: // fall through
|
||||
case IDLE:
|
||||
break; // my preference is to throw IllegalState here, but let it be.
|
||||
case RUNNING: // fall through
|
||||
case RUNNING:
|
||||
_cancelAfterRun = true;
|
||||
return true;
|
||||
case SCHEDULED:
|
||||
boolean cancelled = _future.cancel(false);
|
||||
if (cancelled)
|
||||
@@ -378,27 +393,38 @@ public class SimpleTimer2 {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
run2();
|
||||
} catch (RuntimeException re) {
|
||||
_log.error("timer error", re);
|
||||
throw re;
|
||||
}
|
||||
}
|
||||
|
||||
private void run2() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Running: " + this);
|
||||
long before = System.currentTimeMillis();
|
||||
long delay = 0;
|
||||
synchronized(this) {
|
||||
if (_rescheduleAfterRun)
|
||||
throw new IllegalStateException("rescheduleAfterRun cannot be true here");
|
||||
throw new IllegalStateException(this + " rescheduleAfterRun cannot be true here");
|
||||
|
||||
switch(_state) {
|
||||
case CANCELLED:
|
||||
return; // goodbye
|
||||
case IDLE: // fall through
|
||||
case RUNNING:
|
||||
throw new IllegalStateException("not possible to be in " + _state);
|
||||
case SCHEDULED: // proceed, switch to IDLE in case I need to reschedule
|
||||
_state = TimedEventState.IDLE;
|
||||
throw new IllegalStateException(this + " not possible to be in " + _state);
|
||||
case SCHEDULED:
|
||||
// proceed, will switch to IDLE to reschedule
|
||||
}
|
||||
|
||||
// if I was rescheduled by the user, re-submit myself to the executor.
|
||||
int difference = (int)(_nextRun - before); // careful with long uptimes
|
||||
long difference = _nextRun - before; // careful with long uptimes
|
||||
if (difference > _fuzz) {
|
||||
// proceed, switch to IDLE to reschedule
|
||||
_state = TimedEventState.IDLE;
|
||||
schedule(difference);
|
||||
return;
|
||||
}
|
||||
@@ -411,12 +437,14 @@ public class SimpleTimer2 {
|
||||
if (_future != null)
|
||||
delay = _future.getDelay(TimeUnit.MILLISECONDS);
|
||||
else if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(_pool + " wtf, no _future " + this);
|
||||
_log.warn(_pool + " no _future " + this);
|
||||
// This can be an incorrect warning especially after a schedule(0)
|
||||
if (_log.shouldLog(Log.WARN) && delay > 100)
|
||||
_log.warn(_pool + " wtf, early execution " + delay + ": " + this);
|
||||
else if (_log.shouldLog(Log.WARN) && delay < -1000)
|
||||
_log.warn(" wtf, late execution " + (0 - delay) + ": " + this + _pool.debug());
|
||||
if (_log.shouldWarn()) {
|
||||
if (delay > 100)
|
||||
_log.warn(_pool + " early execution " + delay + ": " + this);
|
||||
else if (delay < -1000)
|
||||
_log.warn(" late execution " + (0 - delay) + ": " + this + _pool.debug());
|
||||
}
|
||||
try {
|
||||
timeReached();
|
||||
} catch (Throwable t) {
|
||||
@@ -426,22 +454,27 @@ public class SimpleTimer2 {
|
||||
switch(_state) {
|
||||
case SCHEDULED: // fall through
|
||||
case IDLE:
|
||||
throw new IllegalStateException("can't be " + _state);
|
||||
throw new IllegalStateException(this + " can't be " + _state);
|
||||
case CANCELLED:
|
||||
break; // nothing
|
||||
case RUNNING:
|
||||
_state = TimedEventState.IDLE;
|
||||
// do we need to reschedule?
|
||||
if (_rescheduleAfterRun) {
|
||||
_rescheduleAfterRun = false;
|
||||
schedule(_nextRun - System.currentTimeMillis());
|
||||
if (_cancelAfterRun) {
|
||||
_cancelAfterRun = false;
|
||||
_state = TimedEventState.CANCELLED;
|
||||
} else {
|
||||
_state = TimedEventState.IDLE;
|
||||
// do we need to reschedule?
|
||||
if (_rescheduleAfterRun) {
|
||||
_rescheduleAfterRun = false;
|
||||
schedule(_nextRun - System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
long time = System.currentTimeMillis() - before;
|
||||
if (time > 500 && _log.shouldLog(Log.WARN))
|
||||
_log.warn(_pool + " wtf, event execution took " + time + ": " + this);
|
||||
_log.warn(_pool + " event execution took " + time + ": " + this);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
// this call is slow - iterates through a HashMap -
|
||||
// would be better to have a local AtomicLong if we care
|
||||
@@ -470,6 +503,7 @@ public class SimpleTimer2 {
|
||||
return _executor.getCompletedTaskCount();
|
||||
}
|
||||
|
||||
/** warning - slow */
|
||||
private String debug() {
|
||||
_executor.purge(); // Remove cancelled tasks from the queue so we get a good queue size stat
|
||||
return
|
||||
@@ -490,10 +524,13 @@ public class SimpleTimer2 {
|
||||
* Schedule periodic event
|
||||
*
|
||||
* @param delay run the first iteration of this event after delay ms
|
||||
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
|
||||
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms, 5000 minimum
|
||||
* @throws IllegalArgumentException if timeoutMs less than 5000
|
||||
*/
|
||||
public PeriodicTimedEvent(SimpleTimer2 pool, long delay, long timeoutMs) {
|
||||
super(pool, delay);
|
||||
if (timeoutMs < 5000)
|
||||
throw new IllegalArgumentException("timeout minimum 5000");
|
||||
_timeoutMs = timeoutMs;
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,8 @@ public abstract class SystemVersion {
|
||||
private static final boolean _isArm = System.getProperty("os.arch").startsWith("arm");
|
||||
private static final boolean _isX86 = System.getProperty("os.arch").contains("86") ||
|
||||
System.getProperty("os.arch").equals("amd64");
|
||||
private static final boolean _isGentoo = System.getProperty("os.version").contains("gentoo") ||
|
||||
System.getProperty("os.version").contains("hardened"); // Funtoo
|
||||
private static final boolean _isAndroid;
|
||||
private static final boolean _isApache;
|
||||
private static final boolean _isGNU;
|
||||
@@ -27,6 +29,7 @@ public abstract class SystemVersion {
|
||||
private static final boolean _oneDotSix;
|
||||
private static final boolean _oneDotSeven;
|
||||
private static final boolean _oneDotEight;
|
||||
private static final boolean _oneDotNine;
|
||||
private static final int _androidSDK;
|
||||
|
||||
static {
|
||||
@@ -62,10 +65,12 @@ public abstract class SystemVersion {
|
||||
_oneDotSix = _androidSDK >= 9;
|
||||
_oneDotSeven = _androidSDK >= 19;
|
||||
_oneDotEight = false;
|
||||
_oneDotNine = false;
|
||||
} else {
|
||||
_oneDotSix = VersionComparator.comp(System.getProperty("java.version"), "1.6") >= 0;
|
||||
_oneDotSeven = _oneDotSix && VersionComparator.comp(System.getProperty("java.version"), "1.7") >= 0;
|
||||
_oneDotEight = _oneDotSeven && VersionComparator.comp(System.getProperty("java.version"), "1.8") >= 0;
|
||||
_oneDotNine = _oneDotEight && VersionComparator.comp(System.getProperty("java.version"), "1.9") >= 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +100,13 @@ public abstract class SystemVersion {
|
||||
return _isGNU;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.23
|
||||
*/
|
||||
public static boolean isGentoo() {
|
||||
return _isGentoo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.8
|
||||
*/
|
||||
@@ -139,6 +151,15 @@ public abstract class SystemVersion {
|
||||
return _oneDotEight;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if Java 1.9 or higher, false for Android.
|
||||
* @since 0.9.23
|
||||
*/
|
||||
public static boolean isJava9() {
|
||||
return _oneDotNine;
|
||||
}
|
||||
|
||||
/**
|
||||
* This isn't always correct.
|
||||
* http://stackoverflow.com/questions/807263/how-do-i-detect-which-kind-of-jre-is-installed-32bit-vs-64bit
|
||||
|
@@ -65,7 +65,7 @@ public abstract class Translate {
|
||||
* The {0} will be replaced by the parameter.
|
||||
* Single quotes must be doubled, i.e. ' -> '' in the string.
|
||||
* @param o parameter, not translated.
|
||||
* To tranlslate parameter also, use _("foo {0} bar", _("baz"))
|
||||
* To tranlslate parameter also, use _t("foo {0} bar", _t("baz"))
|
||||
* Do not double the single quotes in the parameter.
|
||||
* Use autoboxing to call with ints, longs, floats, etc.
|
||||
*/
|
||||
|
@@ -351,7 +351,7 @@ public class TranslateReader extends FilterReader {
|
||||
public void tag(List<String> args) {
|
||||
if (args.size() <= 0)
|
||||
return;
|
||||
_out.print("\t_(");
|
||||
_out.print("\t_t(");
|
||||
for (int i = 0; i < args.size(); i++) {
|
||||
if (i > 0)
|
||||
_out.print(", ");
|
||||
@@ -373,6 +373,9 @@ public class TranslateReader extends FilterReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not comment out, used to extract tags as a part of the build process.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
if (args.length >= 2 && args[0].equals("test"))
|
||||
|
Reference in New Issue
Block a user