diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
new file mode 100644
index 000000000..cb63a80c1
--- /dev/null
+++ b/android/AndroidManifest.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/README.txt b/android/README.txt
new file mode 100644
index 000000000..c9a708263
--- /dev/null
+++ b/android/README.txt
@@ -0,0 +1,18 @@
+#Unzip the android SDK in ../../
+#So then the android tools will be in ../../android-sdk-linux_x86-1.1_r1/tools/
+
+#then build the android apk file:
+ant
+
+#then run the emulator:
+../../android-sdk-linux_x86-1.1_r1/tools/emulator &
+
+#then wait a couple minutes until the emulator is up
+#then install the I2P app
+ant install
+
+#then run the debugger
+../../android-sdk-linux_x86-1.1_r1/tools/ddms &
+
+#to rebuild and reinstall to emulator:
+ant reinstall
diff --git a/android/build.xml b/android/build.xml
new file mode 100644
index 000000000..5875c5fed
--- /dev/null
+++ b/android/build.xml
@@ -0,0 +1,341 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Creating output directories if needed...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Generating R.java / Manifest.java from the resources...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Compiling aidl files into Java classes...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Converting compiled files and external libraries into ${outdir}/${dex-file}...
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging resources and assets...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging resources...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging ${out-debug-package}, and signing it with a debug key...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Packaging ${out-unsigned-package} for release...
+
+
+
+
+
+
+
+
+
+
+
+
+ It will need to be signed with jarsigner before being published.
+
+
+
+
+ Installing ${out-debug-package} onto default emulator...
+
+
+
+
+
+
+
+ Installing ${out-debug-package} onto default emulator...
+
+
+
+
+
+
+
+
+
+ Uninstalling ${application-package} from the default emulator...
+
+
+
+
+
+
+
diff --git a/android/res/layout/main.xml b/android/res/layout/main.xml
new file mode 100644
index 000000000..d76411527
--- /dev/null
+++ b/android/res/layout/main.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
diff --git a/android/res/raw/logger_config b/android/res/raw/logger_config
new file mode 100644
index 000000000..2aeabb9f6
--- /dev/null
+++ b/android/res/raw/logger_config
@@ -0,0 +1,3 @@
+logger.defaultLevel=INFO
+logger.record.net.i2p.router.transport.FIFOBandwidthRefiller=ERROR
+logger.record.net.i2p.stat.Rate=ERROR
diff --git a/android/res/raw/router_config b/android/res/raw/router_config
new file mode 100644
index 000000000..0e7cd2ced
--- /dev/null
+++ b/android/res/raw/router_config
@@ -0,0 +1,9 @@
+# initial router.config
+# save memory
+router.prng.buffers=2
+router.decayingBloomFilterM=20
+stat.full=false
+# no I2CP
+i2p.dummyClientFacade=true
+# for now
+i2np.ntcp.enable=false
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
new file mode 100644
index 000000000..983a304b9
--- /dev/null
+++ b/android/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ I2PAndroid
+
diff --git a/android/src/net/i2p/router/I2PAndroid.java b/android/src/net/i2p/router/I2PAndroid.java
new file mode 100644
index 000000000..bb77d290b
--- /dev/null
+++ b/android/src/net/i2p/router/I2PAndroid.java
@@ -0,0 +1,127 @@
+package net.i2p.router;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.os.Bundle;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import net.i2p.router.Router;
+import net.i2p.router.web.ContextHelper;
+import net.i2p.router.web.ReseedChecker;
+import net.i2p.util.I2PFile;
+
+public class I2PAndroid extends Activity
+{
+ static Context _context;
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ _context = this; // Activity extends Context
+ debugStuff();
+ initialize();
+ }
+
+ public void onRestart()
+ {
+ System.err.println("onRestart called");
+ super.onRestart();
+ }
+
+ public void onStart()
+ {
+ System.err.println("onStart called");
+ super.onStart();
+ Router.main(null);
+ System.err.println("Router.main finished");
+
+ ReseedChecker.checkReseed();
+ }
+
+ public void onResume()
+ {
+ System.err.println("onResume called");
+ super.onResume();
+ }
+
+ public void onPause()
+ {
+ System.err.println("onPause called");
+ super.onPause();
+ }
+
+ public void onStop()
+ {
+ System.err.println("onStop called");
+ super.onStop();
+ // shutdown() doesn't return so use shutdownGracefully()
+ ContextHelper.getContext(null).router().shutdownGracefully(Router.EXIT_HARD);
+ System.err.println("shutdown complete");
+ }
+
+ public void onDestroy()
+ {
+ System.err.println("onDestroy called");
+ super.onDestroy();
+ }
+
+ public static Context getContext() {
+ return _context;
+ }
+
+ private void debugStuff() {
+ System.err.println("java.vendor" + ": " + System.getProperty("java.vendor"));
+ System.err.println("java.version" + ": " + System.getProperty("java.version"));
+ System.err.println("os.arch" + ": " + System.getProperty("os.arch"));
+ System.err.println("os.name" + ": " + System.getProperty("os.name"));
+ System.err.println("os.version" + ": " + System.getProperty("os.version"));
+ System.err.println("user.dir" + ": " + System.getProperty("user.dir"));
+ System.err.println("user.home" + ": " + System.getProperty("user.home"));
+ System.err.println("user.name" + ": " + System.getProperty("user.name"));
+ }
+
+ private void initialize() {
+ // Until we can edit the router.config on the device,
+ // copy it from the resource every time.
+ // File f = new I2PFile("router.config");
+ // if (!f.exists()) {
+ copyResourceToFile(R.raw.router_config, "router.config");
+ copyResourceToFile(R.raw.logger_config, "logger.config");
+ copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
+ // }
+ }
+
+ private void copyResourceToFile(int resID, String f) {
+ InputStream in = null;
+ FileOutputStream out = null;
+
+ System.err.println("Creating file " + f + " from resource");
+ byte buf[] = new byte[4096];
+ try {
+ // Context methods
+ in = getResources().openRawResource(resID);
+ out = openFileOutput(f, 0);
+
+ int read = 0;
+ while ( (read = in.read(buf)) != -1)
+ out.write(buf, 0, read);
+
+ } catch (IOException ioe) {
+ } catch (Resources.NotFoundException nfe) {
+ } finally {
+ if (in != null) try { in.close(); } catch (IOException ioe) {}
+ if (out != null) try { out.close(); } catch (IOException ioe) {}
+ }
+ }
+
+}
diff --git a/android/src/net/i2p/router/web/ReseedChecker.java b/android/src/net/i2p/router/web/ReseedChecker.java
new file mode 100644
index 000000000..8c8ff7bf9
--- /dev/null
+++ b/android/src/net/i2p/router/web/ReseedChecker.java
@@ -0,0 +1,39 @@
+package net.i2p.router.web;
+
+import java.io.File;
+
+import net.i2p.router.web.ReseedHandler;
+import net.i2p.util.I2PFile;
+
+/**
+ * Copied from RouterConsoleRunner.java
+ */
+public class ReseedChecker {
+
+ public static void checkReseed() {
+
+ System.err.println("Checking to see if we should reseed");
+ // we check the i2p installation directory (.) for a flag telling us not to reseed,
+ // but also check the home directory for that flag too, since new users installing i2p
+ // don't have an installation directory that they can put the flag in yet.
+ File noReseedFile = new I2PFile(new I2PFile(System.getProperty("user.home")), ".i2pnoreseed");
+ File noReseedFileAlt1 = new I2PFile(new I2PFile(System.getProperty("user.home")), "noreseed.i2p");
+ File noReseedFileAlt2 = new I2PFile(".i2pnoreseed");
+ File noReseedFileAlt3 = new I2PFile("noreseed.i2p");
+ if (!noReseedFile.exists() && !noReseedFileAlt1.exists() && !noReseedFileAlt2.exists() && !noReseedFileAlt3.exists()) {
+ File netDb = new I2PFile("netDb");
+ // sure, some of them could be "my.info" or various leaseSet- files, but chances are,
+ // if someone has those files, they've already been seeded (at least enough to let them
+ // get i2p started - they can reseed later in the web console)
+ String names[] = (netDb.exists() ? netDb.list() : null);
+ if ( (names == null) || (names.length < 15) ) {
+ System.err.println("Yes, reseeding now");
+ ReseedHandler reseedHandler = new ReseedHandler();
+ reseedHandler.requestReseed();
+ } else {
+ System.err.println("No, we have " + names.length + " routers in the netDb");
+ }
+ }
+ }
+
+}
diff --git a/android/src/net/i2p/util/FileStreamFactory.java b/android/src/net/i2p/util/FileStreamFactory.java
new file mode 100644
index 000000000..b7a65e4f2
--- /dev/null
+++ b/android/src/net/i2p/util/FileStreamFactory.java
@@ -0,0 +1,64 @@
+/*
+ * This is free software, do as you please.
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+import net.i2p.router.I2PAndroid;
+
+/**
+ * Use android static file stream methods
+ * gaaah:
+ * 1) the CWD is /
+ * 2) we can only access /data/data/net.i2p.router/files/
+ * 3) you can't change your CWD in Java
+ * so we have this lovely and the one in I2PFile.
+ *
+ * @author zzz
+ */
+public class FileStreamFactory {
+ private static final String DIR = "/data/data/net.i2p.router/files/";
+
+ /** hopefully no path separators in string */
+ public static FileInputStream getFileInputStream(String f) throws FileNotFoundException {
+ System.err.println("Input file-s: " + I2PAndroid.getContext().getFileStreamPath(f).getAbsolutePath());
+ return I2PAndroid.getContext().openFileInput(f);
+ }
+
+ public static FileInputStream getFileInputStream(File f) throws FileNotFoundException {
+ System.err.println("Input file-f: " + getPath(f) +
+ ' ' + f.getAbsolutePath());
+ //return I2PAndroid.getContext().openFileInput(f.getName());
+ return new FileInputStream(getPath(f));
+ }
+
+ /** hopefully no path separators in string */
+ public static FileOutputStream getFileOutputStream(String f) throws FileNotFoundException {
+ System.err.println("Output file-s: " + I2PAndroid.getContext().getFileStreamPath(f).getAbsolutePath());
+ return I2PAndroid.getContext().openFileOutput(f, 0);
+ }
+
+ public static FileOutputStream getFileOutputStream(File f) throws FileNotFoundException {
+ System.err.println("Output file-f: " + getPath(f) +
+ ' ' + f.getAbsolutePath());
+ //return I2PAndroid.getContext().openFileOutput(f.getName(), 0);
+ return new FileOutputStream(getPath(f));
+ }
+
+ /**
+ * preserve path but convert /foo/blah to /data/data/net.i2p.router/files/foo/blah
+ * Although if the File arg was created with new I2PFile() then this isn't required
+ *
+ */
+ private static String getPath(File f) {
+ String abs = f.getAbsolutePath();
+ if (abs.startsWith(DIR))
+ return abs;
+ return DIR + abs.substring(1); // strip extra '/'
+ }
+}
diff --git a/android/src/net/i2p/util/I2PFile.java b/android/src/net/i2p/util/I2PFile.java
new file mode 100644
index 000000000..94bda029b
--- /dev/null
+++ b/android/src/net/i2p/util/I2PFile.java
@@ -0,0 +1,29 @@
+/*
+ * This is free software, do as you please.
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+
+/**
+ * gaaah:
+ * 1) the CWD is /
+ * 2) we can only access /data/data/net.i2p.router/files/
+ * 3) you can't change your CWD in Java
+ * so we have this lovely and the one in FileStreamFactory.
+ *
+ * @author zzz
+ */
+public class I2PFile extends File {
+
+ public I2PFile (String f) {
+ super("/data/data/net.i2p.router/files/" + f);
+ }
+
+ /** one level deep only */
+ public I2PFile (File p, String f) {
+ super("/data/data/net.i2p.router/files/" + p.getName(), f);
+ }
+
+}
diff --git a/android/src/net/i2p/util/LogWriter.java b/android/src/net/i2p/util/LogWriter.java
new file mode 100644
index 000000000..03f5577ae
--- /dev/null
+++ b/android/src/net/i2p/util/LogWriter.java
@@ -0,0 +1,160 @@
+package net.i2p.util;
+
+/*
+ * public domain
+ *
+ */
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.List;
+
+/**
+ * bridge to android logging
+ *
+ * @author zzz
+ */
+class LogWriter implements Runnable {
+ private final static long CONFIG_READ_ITERVAL = 10 * 1000;
+ private long _lastReadConfig = 0;
+ private long _numBytesInCurrentFile = 0;
+ private OutputStream _currentOut; // = System.out
+ private int _rotationNum = -1;
+ private String _logFilenamePattern;
+ private File _currentFile;
+ private LogManager _manager;
+
+ private boolean _write;
+
+ private LogWriter() { // nop
+ }
+
+ public LogWriter(LogManager manager) {
+ _manager = manager;
+ }
+
+ public void stopWriting() {
+ _write = false;
+ }
+
+ public void run() {
+ _write = true;
+ try {
+ while (_write) {
+ flushRecords();
+ rereadConfig();
+ }
+ System.err.println("Done writing");
+ } catch (Exception e) {
+ System.err.println("Error writing the logs: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ public void flushRecords() { flushRecords(true); }
+ public void flushRecords(boolean shouldWait) {
+ try {
+ List records = _manager._removeAll();
+ if (records == null) return;
+ for (int i = 0; i < records.size(); i++) {
+ LogRecord rec = (LogRecord) records.get(i);
+ writeRecord(rec);
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ } finally {
+ if (shouldWait) {
+ try {
+ synchronized (this) {
+ this.wait(10*1000);
+ }
+ } catch (InterruptedException ie) { // nop
+ }
+ }
+ }
+ }
+
+
+ private void rereadConfig() {
+ long now = Clock.getInstance().now();
+ if (now - _lastReadConfig > CONFIG_READ_ITERVAL) {
+ _manager.rereadConfig();
+ _lastReadConfig = now;
+ }
+ }
+
+ private void writeRecord(LogRecord rec) {
+ if (rec.getThrowable() == null)
+ log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage());
+ else
+ log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
+ }
+
+ public void log(int priority, Class src, String name, String threadName, String msg) {
+ if (src != null) {
+ String tag = src.getName();
+ int dot = tag.lastIndexOf(".");
+ if (dot >= 0)
+ tag = tag.substring(dot + 1);
+ android.util.Log.println(toAndroidLevel(priority),
+ tag,
+ '[' + threadName + "] " + msg);
+ } else if (name != null)
+ android.util.Log.println(toAndroidLevel(priority),
+ name,
+ '[' + threadName + "] " + msg);
+ else
+ android.util.Log.println(toAndroidLevel(priority),
+ threadName, msg);
+ }
+
+ public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) {
+ if (src != null) {
+ String tag = src.getName();
+ int dot = tag.lastIndexOf(".");
+ if (dot >= 0)
+ tag = tag.substring(dot + 1);
+ android.util.Log.println(toAndroidLevel(priority),
+ tag,
+ '[' + threadName + "] " + msg +
+ ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
+ } else if (name != null)
+ android.util.Log.println(toAndroidLevel(priority),
+ name,
+ '[' + threadName + "] " + msg +
+ ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
+ else
+ android.util.Log.println(toAndroidLevel(priority),
+ threadName,
+ msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
+ }
+
+ private static int toAndroidLevel(int level) {
+ switch (level) {
+ case Log.DEBUG:
+ return android.util.Log.DEBUG;
+ case Log.INFO:
+ return android.util.Log.INFO;
+ case Log.WARN:
+ return android.util.Log.WARN;
+ case Log.ERROR:
+ case Log.CRIT:
+ default:
+ return android.util.Log.ERROR;
+ }
+ }
+
+ private static final String replace(String pattern, int num) {
+ char c[] = pattern.toCharArray();
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < c.length; i++) {
+ if ( (c[i] != '#') && (c[i] != '@') )
+ buf.append(c[i]);
+ else
+ buf.append(num);
+ }
+ return buf.toString();
+ }
+}
diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java
index 0aa250654..7d9b28e89 100644
--- a/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java
+++ b/apps/routerconsole/java/src/net/i2p/router/web/ContextHelper.java
@@ -5,7 +5,7 @@ import java.util.List;
import net.i2p.data.Hash;
import net.i2p.router.RouterContext;
-class ContextHelper {
+public class ContextHelper {
public static RouterContext getContext(String contextId) {
List contexts = RouterContext.listContexts();
if ( (contexts == null) || (contexts.size() <= 0) )
diff --git a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java
index 417d0fc72..504b87d76 100644
--- a/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java
+++ b/core/java/src/gnu/crypto/prng/AsyncFortunaStandalone.java
@@ -12,10 +12,11 @@ import net.i2p.util.Log;
* has been eaten)
*/
public class AsyncFortunaStandalone extends FortunaStandalone implements Runnable {
- private static final int BUFFERS = 16;
+ private static final int DEFAULT_BUFFERS = 16;
private static final int BUFSIZE = 256*1024;
- private final byte asyncBuffers[][] = new byte[BUFFERS][BUFSIZE];
- private final int status[] = new int[BUFFERS];
+ private int _bufferCount;
+ private final byte asyncBuffers[][];
+ private final int status[];
private int nextBuf = 0;
private I2PAppContext _context;
private Log _log;
@@ -27,7 +28,10 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
public AsyncFortunaStandalone(I2PAppContext context) {
super();
- for (int i = 0; i < BUFFERS; i++)
+ _bufferCount = context.getProperty("router.prng.buffers", DEFAULT_BUFFERS);
+ asyncBuffers = new byte[_bufferCount][BUFSIZE];
+ status = new int[_bufferCount];
+ for (int i = 0; i < _bufferCount; i++)
status[i] = STATUS_NEED_FILL;
_context = context;
context.statManager().createRateStat("prng.bufferWaitTime", "", "Encryption", new long[] { 60*1000, 10*60*1000, 60*60*1000 } );
@@ -80,11 +84,11 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
status[nextBuf] = STATUS_LIVE;
int prev=nextBuf-1;
if (prev<0)
- prev = BUFFERS-1;
+ prev = _bufferCount-1;
if (status[prev] == STATUS_LIVE)
status[prev] = STATUS_NEED_FILL;
nextBuf++;
- if (nextBuf >= BUFFERS)
+ if (nextBuf >= _bufferCount)
nextBuf = 0;
asyncBuffers.notify();
}
@@ -95,7 +99,7 @@ public class AsyncFortunaStandalone extends FortunaStandalone implements Runnabl
int toFill = -1;
try {
synchronized (asyncBuffers) {
- for (int i = 0; i < BUFFERS; i++) {
+ for (int i = 0; i < _bufferCount; i++) {
if (status[i] == STATUS_NEED_FILL) {
status[i] = STATUS_FILLING;
toFill = i;
diff --git a/core/java/src/net/i2p/crypto/HMAC256Generator.java b/core/java/src/net/i2p/crypto/HMAC256Generator.java
index 2fcaa7b5e..0335d1e7e 100644
--- a/core/java/src/net/i2p/crypto/HMAC256Generator.java
+++ b/core/java/src/net/i2p/crypto/HMAC256Generator.java
@@ -7,7 +7,8 @@ import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.I2PHMac;
/**
* Calculate the HMAC-SHA256 of a key+message. All the good stuff occurs
@@ -19,15 +20,15 @@ public class HMAC256Generator extends HMACGenerator {
public HMAC256Generator(I2PAppContext context) { super(context); }
@Override
- protected HMac acquire() {
+ protected I2PHMac acquire() {
synchronized (_available) {
if (_available.size() > 0)
- return (HMac)_available.remove(0);
+ return (I2PHMac)_available.remove(0);
}
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
// incompatible change, we should update this by removing ", 32"
- return new HMac(new Sha256ForMAC());
+ return new I2PHMac(new Sha256ForMAC());
}
private class Sha256ForMAC extends Sha256Standalone implements Digest {
diff --git a/core/java/src/net/i2p/crypto/HMACGenerator.java b/core/java/src/net/i2p/crypto/HMACGenerator.java
index 8388590a2..29d76cbd2 100644
--- a/core/java/src/net/i2p/crypto/HMACGenerator.java
+++ b/core/java/src/net/i2p/crypto/HMACGenerator.java
@@ -10,7 +10,8 @@ import net.i2p.data.Hash;
import net.i2p.data.SessionKey;
import org.bouncycastle.crypto.digests.MD5Digest;
-import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.crypto.Mac;
+import org.bouncycastle.crypto.macs.I2PHMac;
/**
* Calculate the HMAC-MD5 of a key+message. All the good stuff occurs
@@ -49,7 +50,7 @@ public class HMACGenerator {
if ((key == null) || (key.getData() == null) || (data == null))
throw new NullPointerException("Null arguments for HMAC");
- HMac mac = acquire();
+ I2PHMac mac = acquire();
mac.init(key.getData());
mac.update(data, offset, length);
//byte rv[] = new byte[Hash.HASH_LENGTH];
@@ -73,7 +74,7 @@ public class HMACGenerator {
if ((key == null) || (key.getData() == null) || (curData == null))
throw new NullPointerException("Null arguments for HMAC");
- HMac mac = acquire();
+ Mac mac = acquire();
mac.init(key.getData());
mac.update(curData, curOffset, curLength);
byte rv[] = acquireTmp();
@@ -86,17 +87,17 @@ public class HMACGenerator {
return eq;
}
- protected HMac acquire() {
+ protected I2PHMac acquire() {
synchronized (_available) {
if (_available.size() > 0)
- return (HMac)_available.remove(0);
+ return (I2PHMac)_available.remove(0);
}
// the HMAC is hardcoded to use SHA256 digest size
// for backwards compatability. next time we have a backwards
// incompatible change, we should update this by removing ", 32"
- return new HMac(new MD5Digest(), 32);
+ return new I2PHMac(new MD5Digest(), 32);
}
- private void release(HMac mac) {
+ private void release(Mac mac) {
synchronized (_available) {
if (_available.size() < 64)
_available.add(mac);
@@ -122,4 +123,4 @@ public class HMACGenerator {
_availableTmp.add((Object)tmp);
}
}
-}
\ No newline at end of file
+}
diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java
index 53e32a347..55b424562 100644
--- a/core/java/src/net/i2p/data/DataHelper.java
+++ b/core/java/src/net/i2p/data/DataHelper.java
@@ -37,6 +37,7 @@ import java.util.TreeMap;
import java.util.zip.Deflater;
import net.i2p.util.ByteCache;
+import net.i2p.util.FileStreamFactory;
import net.i2p.util.OrderedProperties;
import net.i2p.util.ReusableGZIPInputStream;
import net.i2p.util.ReusableGZIPOutputStream;
@@ -217,7 +218,7 @@ public class DataHelper {
loadProps(props, file, false);
}
public static void loadProps(Properties props, File file, boolean forceLowerCase) throws IOException {
- loadProps(props, new FileInputStream(file), forceLowerCase);
+ loadProps(props, FileStreamFactory.getFileInputStream(file), forceLowerCase);
}
public static void loadProps(Properties props, InputStream inStr) throws IOException {
loadProps(props, inStr, false);
diff --git a/core/java/src/net/i2p/util/DecayingBloomFilter.java b/core/java/src/net/i2p/util/DecayingBloomFilter.java
index 164c8e453..8c375a66d 100644
--- a/core/java/src/net/i2p/util/DecayingBloomFilter.java
+++ b/core/java/src/net/i2p/util/DecayingBloomFilter.java
@@ -30,6 +30,7 @@ public class DecayingBloomFilter {
private boolean _keepDecaying;
private DecayEvent _decayEvent;
+ private static final int DEFAULT_M = 23;
private static final boolean ALWAYS_MISS = false;
/**
@@ -44,8 +45,12 @@ public class DecayingBloomFilter {
_context = context;
_log = context.logManager().getLog(DecayingBloomFilter.class);
_entryBytes = entryBytes;
- _current = new BloomSHA1(23, 11); //new BloomSHA1(23, 11);
- _previous = new BloomSHA1(23, 11); //new BloomSHA1(23, 11);
+ // this is instantiated in four different places, they may have different
+ // requirements, but for now use this as a gross method of memory reduction.
+ // m == 23 => 2MB each BloomSHA1 (8MB total)
+ int m = context.getProperty("router.decayingBloomFilterM", DEFAULT_M);
+ _current = new BloomSHA1(m, 11); //new BloomSHA1(23, 11);
+ _previous = new BloomSHA1(m, 11); //new BloomSHA1(23, 11);
_durationMs = durationMs;
int numExtenders = (32+ (entryBytes-1))/entryBytes - 1;
if (numExtenders < 0)
diff --git a/core/java/src/net/i2p/util/FileStreamFactory.java b/core/java/src/net/i2p/util/FileStreamFactory.java
new file mode 100644
index 000000000..01d505665
--- /dev/null
+++ b/core/java/src/net/i2p/util/FileStreamFactory.java
@@ -0,0 +1,36 @@
+/*
+ * public domain
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+
+
+/**
+ * This is pulled out and replaced in the android build.
+ *
+ * @author zzz
+ */
+public class FileStreamFactory {
+
+ public static FileInputStream getFileInputStream(String f) throws FileNotFoundException {
+ return new FileInputStream(f);
+ }
+
+ public static FileInputStream getFileInputStream(File f) throws FileNotFoundException {
+ return new FileInputStream(f);
+ }
+
+ public static FileOutputStream getFileOutputStream(String f) throws FileNotFoundException {
+ return new FileOutputStream(f);
+ }
+
+ public static FileOutputStream getFileOutputStream(File f) throws FileNotFoundException {
+ return new FileOutputStream(f);
+ }
+
+}
diff --git a/core/java/src/net/i2p/util/I2PFile.java b/core/java/src/net/i2p/util/I2PFile.java
new file mode 100644
index 000000000..107286edf
--- /dev/null
+++ b/core/java/src/net/i2p/util/I2PFile.java
@@ -0,0 +1,24 @@
+/*
+ * public domain
+ */
+
+package net.i2p.util;
+
+import java.io.File;
+
+/**
+ * This is pulled out and replaced in the android build.
+ *
+ * @author zzz
+ */
+public class I2PFile extends File {
+
+ public I2PFile (String f) {
+ super(f);
+ }
+
+ public I2PFile (File p, String f) {
+ super(p, f);
+ }
+
+}
diff --git a/core/java/src/org/bouncycastle/crypto/macs/HMac.java b/core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java
similarity index 95%
rename from core/java/src/org/bouncycastle/crypto/macs/HMac.java
rename to core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java
index 7176c8aca..a566e8a79 100644
--- a/core/java/src/org/bouncycastle/crypto/macs/HMac.java
+++ b/core/java/src/org/bouncycastle/crypto/macs/I2PHMac.java
@@ -42,8 +42,12 @@ import org.bouncycastle.crypto.Mac;
* a frequently used buffer (called on doFinal). changes released into the public
* domain in 2005.
*
+ * This is renamed from HMac because the constructor HMac(digest, sz) does not exist
+ * in the standard bouncycastle library, thus it conflicts in JVMs that contain the
+ * standard library (Android).
+ *
*/
-public class HMac
+public class I2PHMac
implements Mac
{
private final static int BLOCK_LENGTH = 64;
@@ -56,12 +60,12 @@ implements Mac
private byte[] inputPad = new byte[BLOCK_LENGTH];
private byte[] outputPad = new byte[BLOCK_LENGTH];
- public HMac(
+ public I2PHMac(
Digest digest)
{
this(digest, digest.getDigestSize());
}
- public HMac(
+ public I2PHMac(
Digest digest, int sz)
{
this.digest = digest;
diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java
index 711759a40..f82f9f824 100644
--- a/router/java/src/net/i2p/router/KeyManager.java
+++ b/router/java/src/net/i2p/router/KeyManager.java
@@ -26,6 +26,7 @@ import net.i2p.data.PublicKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.util.Clock;
+import net.i2p.util.FileStreamFactory;
import net.i2p.util.Log;
/**
@@ -203,12 +204,12 @@ public class KeyManager {
FileInputStream in = null;
try {
if (exists) {
- out = new FileOutputStream(keyFile);
+ out = FileStreamFactory.getFileOutputStream(keyFile);
structure.writeBytes(out);
return structure;
} else {
if (keyFile.exists()) {
- in = new FileInputStream(keyFile);
+ in = FileStreamFactory.getFileInputStream(keyFile);
structure.readBytes(in);
return structure;
} else {
diff --git a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
index f3428c447..fea9c461e 100644
--- a/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
+++ b/router/java/src/net/i2p/router/startup/LoadRouterInfoJob.java
@@ -76,7 +76,7 @@ public class LoadRouterInfoJob extends JobImpl {
}
if (_keysExist) {
- fis2 = new FileInputStream(rkf);
+ fis2 = FileStreamFactory.getFileInputStream(rkf);
PrivateKey privkey = new PrivateKey();
privkey.readBytes(fis2);
SigningPrivateKey signingPrivKey = new SigningPrivateKey();