propagate from branch 'i2p.i2p' (head 66743cfb9b4e1c257e4f0a20a318ee7eb1fb607c)

to branch 'i2p.i2p.zzz.multisess' (head 4533ba250cb8e49044f5144b34014e9bc618cdc7)
This commit is contained in:
zzz
2015-04-18 14:08:22 +00:00
346 changed files with 37868 additions and 27424 deletions

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
HashCash implementation. Unused.
</p>
</body>
</html>

View File

@@ -60,7 +60,7 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
{
// http://en.wikipedia.org/wiki/Cpuid
// http://web.archive.org/web/20110307080258/http://www.intel.com/Assets/PDF/appnote/241618.pdf
// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-2a-manual.pdf
// http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-manual-325462.pdf
String modelString = null;
int family = CPUID.getCPUFamily();
int model = CPUID.getCPUModel();
@@ -329,21 +329,31 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
break;
// Ivy Bridge 22 nm
case 0x3a:
modelString = "Ivy Bridge";
modelString = "Ivy Bridge (22nm)";
break;
// Haswell 22 nm
case 0x3c:
modelString = "Haswell";
modelString = "Haswell (22nm)";
break;
// Broadwell 14 nm
case 0x3d:
modelString = "Broadwell";
modelString = "Broadwell (14nm)";
break;
// Ivy Bridge 22 nm
case 0x3e:
modelString = "Xeon Ivy Bridge (22nm)";
break;
// following are for extended model == 4
// most flags are set above
// isCoreiCompatible = true is the default
// 22 nm
case 0x45:
modelString = "Mobile Celeron";
break;
// Atom Silvermont / Bay Trail / Avoton 22 nm
// Supports SSE 4.2
case 0x4d:
@@ -351,8 +361,7 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
modelString = "Bay Trail / Avoton";
break;
// others
// others
default:
modelString = "Intel model " + model;
break;
@@ -361,12 +370,10 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
break;
case 7: {
// Flags TODO
modelString = "Intel Itanium model " + model;
}
break;
// 15 + 0
case 15: {
isPentiumCompatible = true;
isPentiumMMXCompatible = true;
@@ -399,9 +406,7 @@ class IntelInfoImpl extends CPUIDCPUInfo implements IntelCPUInfo
}
break;
// 15 + 1
case 16: {
// Flags TODO
modelString = "Intel Itanium II model " + model;
}
}

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
CPUID implementaion, borrowed from freenet, updated and heavily modified
</p>
</body>
</html>

View File

@@ -0,0 +1,7 @@
<html>
<body>
<p>
The Fortuna PRNG from GNU Crypto, updated and modifed for I2P.
</p>
</body>
</html>

View File

@@ -0,0 +1,8 @@
<html>
<body>
<p>
GettextResource only, for ngettext().
Called only from net.i2p.util.Translate, which is where everything except ngettext is implemented.
</p>
</body>
</html>

View File

@@ -14,9 +14,20 @@ package net.i2p;
*
*/
public class CoreVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = "0.9.18";
public final static String VERSION = "0.9.19";
/**
* For Vuze.
* @return VERSION
* @since 0.9.19
*/
public static String getVersion() {
return VERSION;
}
public static void main(String args[]) {
System.out.println("I2P Core version: " + VERSION);

View File

@@ -406,9 +406,11 @@ public class I2PAppContext {
} else if (_tmpDir.mkdir()) {
_tmpDir.deleteOnExit();
} else {
System.err.println("Could not create temp dir " + _tmpDir.getAbsolutePath());
System.err.println("WARNING: Could not create temp dir " + _tmpDir.getAbsolutePath());
_tmpDir = new SecureDirectory(_routerDir, "tmp");
_tmpDir.mkdir();
_tmpDir.mkdirs();
if (!_tmpDir.exists())
System.err.println("ERROR: Could not create temp dir " + _tmpDir.getAbsolutePath());
}
}
}
@@ -937,6 +939,7 @@ public class I2PAppContext {
/**
* Use instead of SimpleScheduler.getInstance()
* @since 0.9 to replace static instance in the class
* @deprecated in 0.9.20, use simpleTimer2()
*/
public SimpleScheduler simpleScheduler() {
if (!_simpleSchedulerInitialized)
@@ -944,6 +947,9 @@ public class I2PAppContext {
return _simpleScheduler;
}
/**
* @deprecated in 0.9.20
*/
private void initializeSimpleScheduler() {
synchronized (_lock18) {
if (_simpleScheduler == null)

View File

@@ -53,7 +53,7 @@ public interface ClientApp {
public String getName();
/**
* The dislplay name of the ClientApp, used in user interfaces.
* The display name of the ClientApp, used in user interfaces.
* The app must translate.
* @return non-null
*/

View File

@@ -72,6 +72,8 @@ public interface I2PClient {
* the router how to handle the new session, and to configure the end to end
* encryption.
*
* As of 0.9.19, defaults in options are honored.
*
* @param destKeyStream location from which to read the Destination, PrivateKey, and SigningPrivateKey from,
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
* @param options set of options to configure the router with, if null will use System properties

View File

@@ -273,6 +273,8 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* Create a new session, reading the Destination, PrivateKey, and SigningPrivateKey
* from the destKeyStream, and using the specified options to connect to the router
*
* As of 0.9.19, defaults in options are honored.
*
* @param destKeyStream stream containing the private key data,
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
* @param options set of options to configure the router with, if null will use System properties
@@ -412,11 +414,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
}
/** save some memory, don't pass along the pointless properties */
/**
* Save some memory, don't pass along the pointless properties.
* As of 0.9.19, defaults from options will be promoted to real values in rv.
* @return a new Properties without defaults
*/
private Properties filter(Properties options) {
Properties rv = new Properties();
for (Object oKey : options.keySet()) { // TODO-Java6: s/keySet()/stringPropertyNames()/
String key = (String) oKey;
for (String key : options.stringPropertyNames()) {
if (key.startsWith("java.") ||
key.startsWith("user.") ||
key.startsWith("os.") ||
@@ -966,7 +971,9 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
I2PAppContext getContext() { return _context; }
/**
* Retrieve the configuration options
* Retrieve the configuration options, filtered.
* All defaults passed in via constructor have been promoted to the primary map.
*
* @return non-null, if insantiated with null options, this will be the System properties.
*/
Properties getOptions() { return _options; }
@@ -1526,7 +1533,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
boolean close = Boolean.parseBoolean(_options.getProperty("i2cp.closeOnIdle"));
if (reduce || close) {
updateActivity();
_context.simpleScheduler().addEvent(new SessionIdleTimer(_context, this, reduce, close), SessionIdleTimer.MINIMUM_TIME);
_context.simpleTimer2().addEvent(new SessionIdleTimer(_context, this, reduce, close), SessionIdleTimer.MINIMUM_TIME);
}
}

View File

@@ -118,6 +118,6 @@ class SessionIdleTimer implements SimpleTimer.TimedEvent {
} else {
nextDelay = _minimumTime - (now - lastActivity);
}
_context.simpleScheduler().addEvent(this, nextDelay);
_context.simpleTimer2().addEvent(this, nextDelay);
}
}

View File

@@ -2,6 +2,7 @@ package net.i2p.crypto;
import gnu.crypto.hash.Sha256Standalone;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.LinkedBlockingQueue;
@@ -20,6 +21,7 @@ public final class SHA256Generator {
private final LinkedBlockingQueue<MessageDigest> _digests;
private static final boolean _useGnu;
static {
boolean useGnu = false;
try {
@@ -53,13 +55,13 @@ public final class SHA256Generator {
/**
* Calculate the hash and cache the result.
* @param source what to hash
*/
public final Hash calculateHash(byte[] source, int start, int len) {
MessageDigest digest = acquire();
digest.update(source, start, len);
byte rv[] = digest.digest();
release(digest);
//return new Hash(rv);
return Hash.create(rv);
}
@@ -71,9 +73,13 @@ public final class SHA256Generator {
public final void calculateHash(byte[] source, int start, int len, byte out[], int outOffset) {
MessageDigest digest = acquire();
digest.update(source, start, len);
byte rv[] = digest.digest();
release(digest);
System.arraycopy(rv, 0, out, outOffset, rv.length);
try {
digest.digest(out, outOffset, Hash.HASH_LENGTH);
} catch (DigestException e) {
throw new RuntimeException(e);
} finally {
release(digest);
}
}
private MessageDigest acquire() {

View File

@@ -172,11 +172,13 @@ public class DataHelper {
* Property keys and values must not contain '=' or ';', this is not checked and they are not escaped
* Keys and values must be 255 bytes or less,
* Formatted length must not exceed 65535 bytes
* @throws DataFormatException if either is too long.
*
* Properties from the defaults table of props (if any) are not written out by this method.
*
* @param rawStream stream to write to
* @param props properties to write out
* @throws DataFormatException if there is not enough valid data to write out
* @throws DataFormatException if there is not enough valid data to write out,
* or a length limit is exceeded
* @throws IOException if there is an IO error writing out the data
*/
public static void writeProperties(OutputStream rawStream, Properties props)
@@ -190,7 +192,8 @@ public class DataHelper {
* Property keys and values must not contain '=' or ';', this is not checked and they are not escaped
* Keys and values must be 255 bytes or less,
* Formatted length must not exceed 65535 bytes
* @throws DataFormatException if either is too long.
*
* Properties from the defaults table of props (if any) are not written out by this method.
*
* jrandom disabled UTF-8 in mid-2004, for performance reasons,
* i.e. slow foo.getBytes("UTF-8")
@@ -199,6 +202,7 @@ public class DataHelper {
* Use utf8 = false for RouterAddress (fast, non UTF-8)
* Use utf8 = true for SessionConfig (slow, UTF-8)
* @param props source may be null
* @throws DataFormatException if a length limit is exceeded
*/
public static void writeProperties(OutputStream rawStream, Properties props, boolean utf8)
throws DataFormatException, IOException {
@@ -213,6 +217,8 @@ public class DataHelper {
* Keys and values must be 255 bytes or less,
* Formatted length must not exceed 65535 bytes
*
* Properties from the defaults table of props (if any) are not written out by this method.
*
* jrandom disabled UTF-8 in mid-2004, for performance reasons,
* i.e. slow foo.getBytes("UTF-8")
* Re-enable it so we can pass UTF-8 tunnel names through the I2CP SessionConfig.
@@ -269,6 +275,8 @@ public class DataHelper {
* Strings will be UTF-8 encoded in the byte array.
* Warning - confusing method name, Properties is the source.
*
* Properties from the defaults table of props (if any) are not written out by this method.
*
* @deprecated unused
*
* @param target returned array as specified in data structure spec
@@ -364,6 +372,8 @@ public class DataHelper {
* Formatted length must not exceed 65535 bytes
* Warning - confusing method name, Properties is the source.
*
* Properties from the defaults table of props (if any) are not written out by this method.
*
* @throws DataFormatException if key, value, or total is too long
*/
public static byte[] toProperties(Properties opts) throws DataFormatException {
@@ -477,6 +487,8 @@ public class DataHelper {
* Note that this does not escape the \r or \n that are unescaped in loadProps() above.
* As of 0.8.1, file will be mode 600.
*
* Properties from the defaults table of props (if any) are not written out by this method.
*
* Leading or trailing whitespace in values is not checked but
* will be trimmed by loadProps()
*
@@ -1494,11 +1506,11 @@ public class DataHelper {
* @since 0.8.2
*/
public static String formatDuration2(long ms) {
if (ms == 0)
return "0";
String t;
long ams = ms >= 0 ? ms : 0 - ms;
if (ms == 0) {
return "0";
} else if (ams < 3 * 1000) {
if (ams < 3 * 1000) {
// NOTE TO TRANSLATORS: Feel free to translate all these as you see fit, there are several options...
// spaces or not, '.' or not, plural or not. Try not to make it too long, it is used in
// a lot of tables.
@@ -1538,6 +1550,42 @@ public class DataHelper {
return t.replace(" ", "&nbsp;");
}
/**
* Like formatDuration2(long) but with microsec and nanosec also.
*
* @since 0.9.19
*/
public static String formatDuration2(double ms) {
if (ms == 0d)
return "0";
String t;
double adms = ms >= 0 ? ms : 0 - ms;
long lms = (long) ms;
long ams = lms >= 0 ? lms : 0 - lms;
if (adms < 0.000000001d) {
return "0";
} else if (adms < 0.001d) {
t = ngettext("1 ns", "{0,number,###} ns", (int) Math.round(ms * 1000000d));
} else if (adms < 1.0d) {
t = ngettext("1 μs", "{0,number,###} μs", (int) Math.round(ms * 1000d));
} else if (ams < 3 * 1000) {
t = ngettext("1 ms", "{0,number,####} ms", (int) Math.round(ms));
} else if (ams < 2 * 60 * 1000) {
t = ngettext("1 sec", "{0} sec", (int) (ms / 1000));
} else if (ams < 120 * 60 * 1000) {
t = ngettext("1 min", "{0} min", (int) (ms / (60 * 1000)));
} else if (ams < 2 * 24 * 60 * 60 * 1000) {
t = ngettext("1 hour", "{0} hours", (int) (ms / (60 * 60 * 1000)));
} else if (ams > 1000l * 24l * 60l * 60l * 1000l) {
return _("n/a");
} else {
t = ngettext("1 day", "{0} days", (int) (ms / (24 * 60 * 60 * 1000)));
}
if (ms < 0)
t = t.replace("-", "&minus;");
return t.replace(" ", "&nbsp;");
}
private static final String BUNDLE_NAME = "net.i2p.router.web.messages";
private static String _(String key) {

View File

@@ -45,6 +45,10 @@ public class GetDateMessage extends I2CPMessageImpl {
}
/**
* Defaults in GetDateMessage options are, in general, NOT honored.
* Defaults are not serialized out-of-JVM, and the router does not recognize defaults in-JVM.
* Client side must promote defaults to the primary map.
*
* @param version the client's version String to be sent to the router; may be null;
* must be non-null if options is non-null and non-empty.
* @param options Client options to be sent to the router; primarily for authentication; may be null;

View File

@@ -41,15 +41,18 @@ public class SessionConfig extends DataStructureImpl {
private Properties _options;
/**
* if the client authorized this session more than the specified period ago,
* refuse it, since it may be a replay attack
* If the client authorized this session more than the specified period ago,
* refuse it, since it may be a replay attack.
*
* Really? See also ClientManager.REQUEST_LEASESET_TIMEOUT.
* If I2CP replay attacks are a thing, there's a lot more to do.
*/
private final static long OFFSET_VALIDITY = 30 * 1000;
private final static long OFFSET_VALIDITY = 3*60*1000;
public SessionConfig() {
this(null);
}
public SessionConfig(Destination dest) {
_destination = dest;
_creationDate = new Date(Clock.getInstance().now());
@@ -91,6 +94,10 @@ public class SessionConfig extends DataStructureImpl {
* Configure the session with the given options;
* keys and values 255 bytes (not chars) max each
*
* Defaults in SessionConfig options are, in general, NOT honored.
* Defaults are not serialized out-of-JVM, and the router does not recognize defaults in-JVM.
* Client side must promote defaults to the primary map.
*
* @param options Properties for this session
*/
public void setOptions(Properties options) {
@@ -120,6 +127,9 @@ public class SessionConfig extends DataStructureImpl {
/**
* Verify that the signature matches the destination's signing public key.
*
* Note that this also returns false if the creation date is too far in the
* past or future. See tooOld() and getCreationDate().
*
* @return true only if the signature matches
*/
public boolean verifySignature() {
@@ -154,6 +164,9 @@ public class SessionConfig extends DataStructureImpl {
return ok;
}
/**
* Misnamed, could be too old or too far in the future.
*/
public boolean tooOld() {
long now = Clock.getInstance().now();
long earliestValid = now - OFFSET_VALIDITY;

View File

@@ -69,7 +69,7 @@ public final class ByteCache {
/**
* Get a cache responsible for objects of the given size.
* Warning, if you store the result in a static field, the cleaners will
* not operate after a restart on Android, as the old context's SimpleScheduler will have shut down.
* not operate after a restart on Android, as the old context's SimpleTimer2 will have shut down.
* TODO tie this to the context or clean up all calls.
*
* @param cacheSize how large we want the cache to grow
@@ -123,7 +123,7 @@ public final class ByteCache {
_maxCached = maxCachedEntries;
_entrySize = entrySize;
_lastOverflow = -1;
SimpleScheduler.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 777)); //stagger
SimpleTimer2.getInstance().addPeriodicEvent(new Cleanup(), CLEANUP_FREQUENCY + (entrySize % 777)); //stagger
I2PAppContext.getGlobalContext().statManager().createRateStat("byteCache.memory." + entrySize, "Memory usage (B)", "Router", new long[] { 10*60*1000 });
}

View File

@@ -904,10 +904,14 @@ public class EepGet {
_keepFetching = false;
_notModified = true;
return;
case 400: // bad req
case 401: // server auth
case 403: // bad req
case 404: // not found
case 408: // req timeout
case 409: // bad addr helper
case 414: // URI too long
case 431: // headers too long
case 503: // no outproxy
_transferFailed = true;
if (_alreadyTransferred > 0 || !_shouldWriteErrorToOutput) {

View File

@@ -266,7 +266,7 @@ public class I2PSSLSocketFactory {
for (int i = 0; i < p.length; i++) {
// if we left SSLv3 in there, we don't support TLS,
// so we should't remove the SSL ciphers
if (p.equals("SSLv3"))
if (p[i].equals("SSLv3"))
return;
}
socket.setEnabledProtocols(p);

View File

@@ -74,6 +74,9 @@ class LogWriter extends LogWriterBase {
}
}
/**
* @since 0.9.19
*/
protected void flushWriter() {
try {
if (_currentOut != null)
@@ -84,6 +87,9 @@ class LogWriter extends LogWriterBase {
}
}
/**
* @since 0.9.19 renamed from closeFile()
*/
protected void closeWriter() {
Writer out = _currentOut;
if (out != null) {

View File

@@ -16,6 +16,7 @@ import java.util.Queue;
* the log. This also periodically instructs the LogManager to reread its config
* file.
*
* @since 0.9.19 pulled from LogWriter so Android may extend
*/
abstract class LogWriterBase implements Runnable {
/** every 10 seconds? why? Just have the gui force a reread after a change?? */

View File

@@ -196,14 +196,15 @@ public class NativeBigInteger extends BigInteger {
private final static String sCPUType; //The CPU Type to optimize for (one of the above strings)
static {
if (_isX86) // Don't try to resolve CPU type on non x86 hardware
if (_isX86) { // Don't try to resolve CPU type on non x86 hardware
sCPUType = resolveCPUType();
else if (_isArm)
} else if (_isArm) {
sCPUType = JBIGI_OPTIMIZATION_ARM;
else if (_isPPC && !_isMac)
sCPUType = JBIGI_OPTIMIZATION_PPC;
else
sCPUType = null;
} else if (_isPPC && !_isMac) {
sCPUType = JBIGI_OPTIMIZATION_PPC;
} else {
sCPUType = null;
}
loadNative();
}

View File

@@ -24,12 +24,15 @@ import net.i2p.I2PAppContext;
* For periodic events, use addPeriodicEvent(). Unlike SimpleTimer,
* uncaught Exceptions will not prevent subsequent executions.
*
* @deprecated in 0.9.20, use SimpleTimer2 instead
*
* @author zzz
*/
public class SimpleScheduler {
/**
* If you have a context, use context.simpleScheduler() instead
* @deprecated in 0.9.20, replaced by SimpleTimer2
*/
public static SimpleScheduler getInstance() {
return I2PAppContext.getGlobalContext().simpleScheduler();
@@ -46,6 +49,7 @@ public class SimpleScheduler {
/**
* To be instantiated by the context.
* Others should use context.simpleTimer() instead
* @deprecated in 0.9.20, replaced by SimpleTimer2
*/
public SimpleScheduler(I2PAppContext context) {
this(context, "SimpleScheduler");
@@ -54,6 +58,7 @@ public class SimpleScheduler {
/**
* To be instantiated by the context.
* Others should use context.simpleTimer() instead
* @deprecated in 0.9.20, replaced by SimpleTimer2
*/
private SimpleScheduler(I2PAppContext context, String name) {
_log = context.logManager().getLog(SimpleScheduler.class);

View File

@@ -14,7 +14,7 @@ import net.i2p.I2PAppContext;
* they b0rk the timer).
*
* WARNING - Deprecated.
* This is an inefficient mess. Use SimpleScheduler or SimpleTimer2 if possible.
* This is an inefficient mess. Use SimpleTimer2 if possible.
*/
public class SimpleTimer {

View File

@@ -124,6 +124,61 @@ public class SimpleTimer2 {
private ScheduledFuture schedule(TimedEvent t, long timeoutMs) {
return _executor.schedule(t, timeoutMs, TimeUnit.MILLISECONDS);
}
/**
* Queue up the given event to be fired no sooner than timeoutMs from now.
*
* @param event
* @param timeoutMs
*/
public void addEvent(final SimpleTimer.TimedEvent event, final long timeoutMs) {
if (event == null)
throw new IllegalArgumentException("addEvent null");
new TimedEvent(this, timeoutMs) {
@Override
public void timeReached() {
event.timeReached();
}
};
}
/**
* Schedule periodic event
*
* The TimedEvent must not do its own rescheduling.
* As all Exceptions are caught in run(), these will not prevent
* subsequent executions (unlike SimpleTimer, where the TimedEvent does
* its own rescheduling).
*
* @since 0.9.20
* @param timeoutMs run subsequent iterations of this event every timeoutMs ms
*/
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long timeoutMs) {
addPeriodicEvent(event, timeoutMs, timeoutMs);
}
/**
* Schedule periodic event
*
* The TimedEvent must not do its own rescheduling.
* As all Exceptions are caught in run(), these will not prevent
* subsequent executions (unlike SimpleTimer, where the TimedEvent does
* its own rescheduling).
*
* @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
*/
public void addPeriodicEvent(final SimpleTimer.TimedEvent event, final long delay, final long timeoutMs) {
new PeriodicTimedEvent(this, delay, timeoutMs) {
@Override
public void timeReached() {
event.timeReached();
}
};
}
/**
* state of a given TimedEvent
@@ -141,6 +196,7 @@ public class SimpleTimer2 {
CANCELLED
};
/**
* Similar to SimpleTimer.TimedEvent but users must extend instead of implement,
* and all schedule and cancel methods are through this class rather than SimpleTimer2.
@@ -228,7 +284,6 @@ public class SimpleTimer2 {
break;
case SCHEDULED: // nothing
}
}
/**
@@ -403,5 +458,26 @@ public class SimpleTimer2 {
" Completed: " + _executor.getCompletedTaskCount() +
" Queued: " + _executor.getQueue().size();
}
public static abstract class PeriodicTimedEvent extends TimedEvent {
private long _timeoutMs;
/**
* 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
*/
public PeriodicTimedEvent(SimpleTimer2 pool, long delay, long timeoutMs) {
super(pool, delay);
_timeoutMs = timeoutMs;
}
@Override
public void run() {
super.run();
schedule(_timeoutMs);
}
}
}

View File

@@ -69,7 +69,7 @@ public class BSkipSpan extends SkipSpan {
protected int overflowPage;
protected int prevPage;
protected int nextPage;
protected int nextPage = 0;
protected Serializer keySer;
protected Serializer valSer;

View File

@@ -0,0 +1,14 @@
<html>
<body>
<p>
This is from some very old version of bouncycastle, part of package org.bouncycastle.crypto.
Android bundled something similar in pre-Gingerbread, but upgraded to a later, incompatible version
in Gingerbread. As of Java 1.4 these are in javax.crypto - more or less.
To avoid having to make two different versions of our Android app, we rename to org.bouncycastle.oldcrypto.
</p><p>
Ref: <a href="http://docs.oracle.com/javase/1.5.0/docs/api/javax/crypto/package-summary.html">javax.crypto</a>
and
<a href="http://code.google.com/p/android/issues/detail?id=3280">this android issue</a>.
</p>
</body>
</html>