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();