merge of '0738aeef8a1d4e9ca82dc5ba0077d83a57c47f81'

and '9625ea3e96d57df74bc62018bf64230a22c49ce0'
This commit is contained in:
z3d
2010-10-13 16:07:33 +00:00
149 changed files with 2721 additions and 1741 deletions

View File

@ -31,6 +31,7 @@ import net.i2p.util.KeyRing;
import net.i2p.util.LogManager;
//import net.i2p.util.PooledRandomSource;
import net.i2p.util.RandomSource;
import net.i2p.util.SecureDirectory;
/**
* <p>Provide a base scope for accessing singletons that I2P exposes. Rather than
@ -218,7 +219,7 @@ public class I2PAppContext {
// config defaults to base
s = getProperty("i2p.dir.config");
if (s != null) {
_configDir = new File(s);
_configDir = new SecureDirectory(s);
if (!_configDir.exists())
_configDir.mkdir();
} else {
@ -227,7 +228,7 @@ public class I2PAppContext {
// router defaults to config
s = getProperty("i2p.dir.router");
if (s != null) {
_routerDir = new File(s);
_routerDir = new SecureDirectory(s);
if (!_routerDir.exists())
_routerDir.mkdir();
} else {
@ -241,7 +242,7 @@ public class I2PAppContext {
// these all default to router
s = getProperty("i2p.dir.log");
if (s != null) {
_logDir = new File(s);
_logDir = new SecureDirectory(s);
if (!_logDir.exists())
_logDir.mkdir();
} else {
@ -249,7 +250,7 @@ public class I2PAppContext {
}
s = getProperty("i2p.dir.app");
if (s != null) {
_appDir = new File(s);
_appDir = new SecureDirectory(s);
if (!_appDir.exists())
_appDir.mkdir();
} else {
@ -345,14 +346,14 @@ public class I2PAppContext {
String d = getProperty("i2p.dir.temp", System.getProperty("java.io.tmpdir"));
// our random() probably isn't warmed up yet
String f = "i2p-" + Math.abs((new java.util.Random()).nextInt()) + ".tmp";
_tmpDir = new File(d, f);
_tmpDir = new SecureDirectory(d, f);
if (_tmpDir.exists()) {
// good or bad ?
} else if (_tmpDir.mkdir()) {
_tmpDir.deleteOnExit();
} else {
System.err.println("Could not create temp dir " + _tmpDir.getAbsolutePath());
_tmpDir = new File(_routerDir, "tmp");
_tmpDir = new SecureDirectory(_routerDir, "tmp");
_tmpDir.mkdir();
}
}

View File

@ -18,9 +18,9 @@ import net.i2p.util.Log;
* @author jrandom
*/
abstract class HandlerImpl implements I2CPMessageHandler {
protected Log _log;
private int _type;
protected I2PAppContext _context;
protected final Log _log;
private final int _type;
protected final I2PAppContext _context;
public HandlerImpl(I2PAppContext context, int type) {
_context = context;

View File

@ -34,6 +34,8 @@ public interface I2PClient {
public final static String PROP_RELIABILITY_BEST_EFFORT = "BestEffort";
/** Reliability value: guaranteed */
public final static String PROP_RELIABILITY_GUARANTEED = "Guaranteed";
/** @since 0.8.1 */
public final static String PROP_RELIABILITY_NONE = "none";
/** protocol flag that must be sent when opening the i2cp connection to the router */
public final static int PROTOCOL_BYTE = 0x2A;
@ -64,4 +66,4 @@ public interface I2PClient {
* @return newly created destination
*/
public Destination createDestination(OutputStream destKeyStream, Certificate cert) throws I2PException, IOException;
}
}

View File

@ -33,12 +33,14 @@ import net.i2p.util.Log;
class I2PSessionImpl2 extends I2PSessionImpl {
/** set of MessageState objects, representing all of the messages in the process of being sent */
private /* FIXME final FIXME */ Set _sendingStates;
private /* FIXME final FIXME */ Set<MessageState> _sendingStates;
/** max # seconds to wait for confirmation of the message send */
private final static long SEND_TIMEOUT = 60 * 1000; // 60 seconds to send
/** should we gzip each payload prior to sending it? */
private final static boolean SHOULD_COMPRESS = true;
private final static boolean SHOULD_DECOMPRESS = true;
/** Don't expect any MSMs from the router for outbound traffic @since 0.8.1 */
private boolean _noEffort;
/** for extension */
public I2PSessionImpl2() {}
@ -53,6 +55,8 @@ class I2PSessionImpl2 extends I2PSessionImpl {
super(ctx, destKeyStream, options);
_log = ctx.logManager().getLog(I2PSessionImpl2.class);
_sendingStates = new HashSet(32);
// default is BestEffort
_noEffort = "none".equalsIgnoreCase(options.getProperty(I2PClient.PROP_RELIABILITY));
ctx.statManager().createRateStat("i2cp.sendBestEffortTotalTime", "how long to do the full sendBestEffort call?", "i2cp", new long[] { 10*60*1000 } );
//ctx.statManager().createRateStat("i2cp.sendBestEffortStage0", "first part of sendBestEffort?", "i2cp", new long[] { 10*60*1000 } );
@ -60,15 +64,16 @@ class I2PSessionImpl2 extends I2PSessionImpl {
//ctx.statManager().createRateStat("i2cp.sendBestEffortStage2", "third part of sendBestEffort?", "i2cp", new long[] { 10*60*1000 } );
//ctx.statManager().createRateStat("i2cp.sendBestEffortStage3", "fourth part of sendBestEffort?", "i2cp", new long[] { 10*60*1000 } );
//ctx.statManager().createRateStat("i2cp.sendBestEffortStage4", "fifth part of sendBestEffort?", "i2cp", new long[] { 10*60*1000 } );
_context.statManager().createRateStat("i2cp.receiveStatusTime.0", "How long it took to get status=0 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.1", "How long it took to get status=1 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.2", "How long it took to get status=2 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.3", "How long it took to get status=3 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.4", "How long it took to get status=4 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.5", "How long it took to get status=5 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime", "How long it took to get any status", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.tx.msgCompressed", "compressed size transferred", "i2cp", new long[] { 60*1000, 30*60*1000 });
_context.statManager().createRateStat("i2cp.tx.msgExpanded", "size before compression", "i2cp", new long[] { 60*1000, 30*60*1000 });
//_context.statManager().createRateStat("i2cp.receiveStatusTime.0", "How long it took to get status=0 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.1", "How long it took to get status=1 back", "i2cp", new long[] { 10*60*1000 });
// best effort codes unused
//_context.statManager().createRateStat("i2cp.receiveStatusTime.2", "How long it took to get status=2 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
//_context.statManager().createRateStat("i2cp.receiveStatusTime.3", "How long it took to get status=3 back", "i2cp", new long[] { 60*1000, 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.4", "How long it took to get status=4 back", "i2cp", new long[] { 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime.5", "How long it took to get status=5 back", "i2cp", new long[] { 10*60*1000 });
_context.statManager().createRateStat("i2cp.receiveStatusTime", "How long it took to get any status", "i2cp", new long[] { 10*60*1000 });
_context.statManager().createRateStat("i2cp.tx.msgCompressed", "compressed size transferred", "i2cp", new long[] { 30*60*1000 });
_context.statManager().createRateStat("i2cp.tx.msgExpanded", "size before compression", "i2cp", new long[] { 30*60*1000 });
}
protected long getTimeout() {
@ -186,7 +191,10 @@ class I2PSessionImpl2 extends I2PSessionImpl {
}
_context.statManager().addRateData("i2cp.tx.msgCompressed", compressed, 0);
_context.statManager().addRateData("i2cp.tx.msgExpanded", size, 0);
return sendBestEffort(dest, payload, keyUsed, tagsSent, expires);
if (_noEffort)
return sendNoEffort(dest, payload, expires);
else
return sendBestEffort(dest, payload, keyUsed, tagsSent, expires);
}
/**
@ -213,6 +221,9 @@ class I2PSessionImpl2 extends I2PSessionImpl {
private static final int NUM_TAGS = 50;
/**
* TODO - Don't need to save MessageState since actuallyWait is false...
* But for now just use sendNoEffort() instead.
*
* @param keyUsed unused - no end-to-end crypto
* @param tagsSent unused - no end-to-end crypto
*/
@ -257,7 +268,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
+ "ms left, " + oldTags + " tags known and "
+ (tag == null ? "no tag" : " a valid tag"));
}
if (false) // rekey
newKey = _context.keyGenerator().generateSessionKey();
@ -371,6 +382,37 @@ class I2PSessionImpl2 extends I2PSessionImpl {
return found;
}
/**
* Same as sendBestEffort(), except we do not expect any MessageStatusMessage responses -
* not for accepted, or success, or failure.
* So we don't create a MessageState and save it on the _sendingStates HashSet
*
* @return true always
* @since 0.8.1
*/
protected boolean sendNoEffort(Destination dest, byte payload[], long expires)
throws I2PSessionException {
// nonce always 0
_producer.sendMessage(this, dest, 0, payload, null, null, null, null, expires);
return true;
}
/**
* Only call this with nonzero status, i.e. for outbound messages
* whose MessageState may be queued on _sendingStates.
*
* Even when using sendBestEffort(), this is a waste, because the
* MessageState is removed from _sendingStates immediately and
* so the lookup here fails.
* And iterating through the HashSet instead of having a map
* is bad too.
*
* This is now pretty much avoided since streaming now sets
* i2cp.messageReliability = none, which forces sendNoEffort() instead of sendBestEffort(),
* so the router won't send us any MSM's for outbound traffic.
*
* @param status != 0
*/
@Override
public void receiveStatus(int msgId, long nonce, int status) {
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Received status " + status + " for msgId " + msgId + " / " + nonce);
@ -413,12 +455,13 @@ class I2PSessionImpl2 extends I2PSessionImpl {
case 1:
_context.statManager().addRateData("i2cp.receiveStatusTime.1", lifetime, 0);
break;
case 2:
_context.statManager().addRateData("i2cp.receiveStatusTime.2", lifetime, 0);
break;
case 3:
_context.statManager().addRateData("i2cp.receiveStatusTime.3", lifetime, 0);
break;
// best effort codes unused
//case 2:
// _context.statManager().addRateData("i2cp.receiveStatusTime.2", lifetime, 0);
// break;
//case 3:
// _context.statManager().addRateData("i2cp.receiveStatusTime.3", lifetime, 0);
// break;
case 4:
_context.statManager().addRateData("i2cp.receiveStatusTime.4", lifetime, 0);
break;

View File

@ -37,13 +37,7 @@ class MessageState {
_context = ctx;
_nonce = nonce;
_prefix = prefix + "[" + _stateId + "]: ";
_id = null;
_receivedStatus = new HashSet();
_cancelled = false;
_key = null;
_newKey = null;
_tags = null;
_to = null;
_created = ctx.clock().now();
//ctx.statManager().createRateStat("i2cp.checkStatusTime", "how long it takes to go through the states", "i2cp", new long[] { 60*1000 });
}

View File

@ -18,13 +18,13 @@ import net.i2p.util.SimpleTimer;
*
* @author zzz
*/
public class SessionIdleTimer implements SimpleTimer.TimedEvent {
class SessionIdleTimer implements SimpleTimer.TimedEvent {
public static final long MINIMUM_TIME = 5*60*1000;
private static final long DEFAULT_REDUCE_TIME = 20*60*1000;
private static final long DEFAULT_CLOSE_TIME = 30*60*1000;
private final static Log _log = new Log(SessionIdleTimer.class);
private I2PAppContext _context;
private I2PSessionImpl _session;
private final I2PAppContext _context;
private final I2PSessionImpl _session;
private boolean _reduceEnabled;
private int _reduceQuantity;
private long _reduceTime;
@ -36,7 +36,6 @@ public class SessionIdleTimer implements SimpleTimer.TimedEvent {
/**
* reduce, shutdown, or both must be true
*/
/* FIXME Exporting non-public type through public API FIXME */
public SessionIdleTimer(I2PAppContext context, I2PSessionImpl session, boolean reduce, boolean shutdown) {
_context = context;
_session = session;

View File

@ -66,6 +66,10 @@ public class EepGetNamingService extends NamingService {
hostname = hostname.toLowerCase();
// If you want b32, chain with HostsTxtNamingService
if (hostname.length() == 60 && hostname.endsWith(".b32.i2p"))
return null;
// check the cache
Destination d = getCache(hostname);
if (d != null)

View File

@ -66,6 +66,10 @@ public class ExecNamingService extends NamingService {
hostname = hostname.toLowerCase();
// If you want b32, chain with HostsTxtNamingService
if (hostname.length() == 60 && hostname.endsWith(".b32.i2p"))
return null;
// check the cache
Destination d = getCache(hostname);
if (d != null)

View File

@ -27,6 +27,7 @@ class LookupDest {
protected LookupDest(I2PAppContext context) {}
/** @param key 52 chars (do not include the .b32.i2p suffix) */
static Destination lookupBase32Hash(I2PAppContext ctx, String key) {
byte[] h = Base32.decode(key);
if (h == null)
@ -44,6 +45,7 @@ class LookupDest {
}
****/
/** @param h 32 byte hash */
static Destination lookupHash(I2PAppContext ctx, byte[] h) {
Hash key = new Hash(h);
Destination rv = null;

View File

@ -32,7 +32,7 @@ public abstract class NamingService {
public static final String PROP_IMPL = "i2p.naming.impl";
private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService";
protected static final int CACHE_MAX_SIZE = 8;
protected static final int CACHE_MAX_SIZE = 16;
/**
@ -107,7 +107,7 @@ public abstract class NamingService {
* The service may override the age and/or size limit
*/
/** Don't know why a dest would ever change but keep this short anyway */
protected static final long CACHE_MAX_AGE = 60*1000;
protected static final long CACHE_MAX_AGE = 7*60*1000;
private class CacheEntry {
public Destination dest;
@ -174,4 +174,11 @@ public abstract class NamingService {
return ce.dest;
}
}
/** @since 0.8.1 */
public void clearCache() {
synchronized (_cache) {
_cache.clear();
}
}
}

View File

@ -1,7 +1,6 @@
package net.i2p.crypto;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
/**
* Cache the objects used in CryptixRijndael_Algorithm.makeKey to reduce
@ -11,7 +10,7 @@ import java.util.List;
*
*/
public final class CryptixAESKeyCache {
private final List _availableKeys;
private final LinkedBlockingQueue<KeyCacheEntry> _availableKeys;
private static final int KEYSIZE = 32; // 256bit AES
private static final int BLOCKSIZE = 16;
@ -22,7 +21,7 @@ public final class CryptixAESKeyCache {
private static final int MAX_KEYS = 64;
public CryptixAESKeyCache() {
_availableKeys = new ArrayList(MAX_KEYS);
_availableKeys = new LinkedBlockingQueue(MAX_KEYS);
}
/**
@ -30,10 +29,9 @@ public final class CryptixAESKeyCache {
*
*/
public final KeyCacheEntry acquireKey() {
synchronized (_availableKeys) {
if (!_availableKeys.isEmpty())
return (KeyCacheEntry)_availableKeys.remove(0);
}
KeyCacheEntry rv = _availableKeys.poll();
if (rv != null)
return rv;
return createNew();
}
@ -42,10 +40,7 @@ public final class CryptixAESKeyCache {
*
*/
public final void releaseKey(KeyCacheEntry key) {
synchronized (_availableKeys) {
if (_availableKeys.size() < MAX_KEYS)
_availableKeys.add(key);
}
_availableKeys.offer(key);
}
public static final KeyCacheEntry createNew() {

View File

@ -65,35 +65,17 @@ public class DHSessionKeyBuilder {
public final static String PROP_DH_PRECALC_MIN = "crypto.dh.precalc.min";
public final static String PROP_DH_PRECALC_MAX = "crypto.dh.precalc.max";
public final static String PROP_DH_PRECALC_DELAY = "crypto.dh.precalc.delay";
public final static String DEFAULT_DH_PRECALC_MIN = "5";
public final static String DEFAULT_DH_PRECALC_MAX = "50";
public final static String DEFAULT_DH_PRECALC_DELAY = "10000";
public final static int DEFAULT_DH_PRECALC_MIN = 5;
public final static int DEFAULT_DH_PRECALC_MAX = 50;
public final static int DEFAULT_DH_PRECALC_DELAY = 10000;
static {
I2PAppContext ctx = _context;
ctx.statManager().createRateStat("crypto.dhGeneratePublicTime", "How long it takes to create x and X", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
ctx.statManager().createRateStat("crypto.dhCalculateSessionTime", "How long it takes to create the session key", "Encryption", new long[] { 60*1000, 5*60*1000, 60*60*1000 });
try {
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN));
MIN_NUM_BUILDERS = val;
} catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_DH_PRECALC_MIN);
MIN_NUM_BUILDERS = val;
}
try {
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX));
MAX_NUM_BUILDERS = val;
} catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_DH_PRECALC_MAX);
MAX_NUM_BUILDERS = val;
}
try {
int val = Integer.parseInt(ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY));
CALC_DELAY = val;
} catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_DH_PRECALC_DELAY);
CALC_DELAY = val;
}
MIN_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN);
MAX_NUM_BUILDERS = ctx.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX);
CALC_DELAY = ctx.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY);
if (_log.shouldLog(Log.DEBUG))
_log.debug("DH Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "

View File

@ -41,6 +41,10 @@ import net.i2p.data.SigningPublicKey;
import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger;
/**
* Params and rv's changed from Hash to SHA1Hash for version 0.8.1
* There shouldn't be any external users of those variants.
*/
public class DSAEngine {
private Log _log;
private I2PAppContext _context;
@ -61,7 +65,9 @@ public class DSAEngine {
public boolean verifySignature(Signature signature, InputStream in, SigningPublicKey verifyingKey) {
return verifySignature(signature, calculateHash(in), verifyingKey);
}
public boolean verifySignature(Signature signature, Hash hash, SigningPublicKey verifyingKey) {
/** @param hash SHA-1 hash, NOT a SHA-256 hash */
public boolean verifySignature(Signature signature, SHA1Hash hash, SigningPublicKey verifyingKey) {
long start = _context.clock().now();
try {
@ -111,17 +117,18 @@ public class DSAEngine {
}
public Signature sign(byte data[], int offset, int length, SigningPrivateKey signingKey) {
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
Hash h = calculateHash(data, offset, length);
SHA1Hash h = calculateHash(data, offset, length);
return sign(h, signingKey);
}
public Signature sign(InputStream in, SigningPrivateKey signingKey) {
if ((signingKey == null) || (in == null) ) return null;
Hash h = calculateHash(in);
SHA1Hash h = calculateHash(in);
return sign(h, signingKey);
}
public Signature sign(Hash hash, SigningPrivateKey signingKey) {
/** @param hash SHA-1 hash, NOT a SHA-256 hash */
public Signature sign(SHA1Hash hash, SigningPrivateKey signingKey) {
if ((signingKey == null) || (hash == null)) return null;
long start = _context.clock().now();
@ -186,7 +193,8 @@ public class DSAEngine {
return sig;
}
public Hash calculateHash(InputStream in) {
/** @return hash SHA-1 hash, NOT a SHA-256 hash */
public SHA1Hash calculateHash(InputStream in) {
SHA1 digest = new SHA1();
byte buf[] = new byte[64];
int read = 0;
@ -199,14 +207,15 @@ public class DSAEngine {
_log.warn("Unable to hash the stream", ioe);
return null;
}
return new Hash(digest.engineDigest());
return new SHA1Hash(digest.engineDigest());
}
public static Hash calculateHash(byte[] source, int offset, int len) {
/** @return hash SHA-1 hash, NOT a SHA-256 hash */
public static SHA1Hash calculateHash(byte[] source, int offset, int len) {
SHA1 h = new SHA1();
h.engineUpdate(source, offset, len);
byte digested[] = h.digest();
return new Hash(digested);
return new SHA1Hash(digested);
}
public static void main(String args[]) {

View File

@ -15,16 +15,16 @@ import org.bouncycastle.crypto.macs.I2PHMac;
* in {@link org.bouncycastle.crypto.macs.I2PHMac} and
* {@link org.bouncycastle.crypto.digests.MD5Digest}.
*
* deprecated unused
*/
public class HMAC256Generator extends HMACGenerator {
public HMAC256Generator(I2PAppContext context) { super(context); }
@Override
protected I2PHMac acquire() {
synchronized (_available) {
if (!_available.isEmpty())
return (I2PHMac)_available.remove(0);
}
I2PHMac rv = _available.poll();
if (rv != null)
return rv;
// 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"
@ -43,6 +43,7 @@ public class HMAC256Generator extends HMACGenerator {
}
/******
public static void main(String args[]) {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
byte data[] = new byte[64];
@ -51,4 +52,5 @@ public class HMAC256Generator extends HMACGenerator {
Hash mac = ctx.hmac256().calculate(key, data);
System.out.println(Base64.encode(mac.getData()));
}
******/
}

View File

@ -1,8 +1,7 @@
package net.i2p.crypto;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
@ -22,14 +21,14 @@ import org.bouncycastle.crypto.macs.I2PHMac;
public class HMACGenerator {
private I2PAppContext _context;
/** set of available HMAC instances for calculate */
protected final List _available;
protected final LinkedBlockingQueue<I2PHMac> _available;
/** set of available byte[] buffers for verify */
private final List _availableTmp;
private final LinkedBlockingQueue<byte[]> _availableTmp;
public HMACGenerator(I2PAppContext context) {
_context = context;
_available = new ArrayList(32);
_availableTmp = new ArrayList(32);
_available = new LinkedBlockingQueue(32);
_availableTmp = new LinkedBlockingQueue(32);
}
/**
@ -88,39 +87,30 @@ public class HMACGenerator {
}
protected I2PHMac acquire() {
synchronized (_available) {
if (!_available.isEmpty())
return (I2PHMac)_available.remove(0);
}
I2PHMac rv = _available.poll();
if (rv != null)
return rv;
// 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 I2PHMac(new MD5Digest(), 32);
}
private void release(Mac mac) {
synchronized (_available) {
if (_available.size() < 64)
_available.add(mac);
}
private void release(I2PHMac mac) {
_available.offer(mac);
}
// temp buffers for verify(..)
private byte[] acquireTmp() {
byte rv[] = null;
synchronized (_availableTmp) {
if (!_availableTmp.isEmpty())
rv = (byte[])_availableTmp.remove(0);
}
byte rv[] = _availableTmp.poll();
if (rv != null)
Arrays.fill(rv, (byte)0x0);
else
rv = new byte[Hash.HASH_LENGTH];
return rv;
}
private void releaseTmp(byte tmp[]) {
synchronized (_availableTmp) {
if (_availableTmp.size() < 64)
_availableTmp.add((Object)tmp);
}
_availableTmp.offer(tmp);
}
}

View File

@ -63,7 +63,7 @@ public final class SHA1 extends MessageDigest implements Cloneable {
/**
* This implementation returns a fixed-size digest.
*/
private static final int HASH_LENGTH = 20; // bytes == 160 bits
static final int HASH_LENGTH = 20; // bytes == 160 bits
/**
* Private context for incomplete blocks and padding bytes.

View File

@ -0,0 +1,81 @@
package net.i2p.crypto;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl;
/**
* Because DSAEngine was abusing Hash for 20-byte hashes
*
* @since 0.8.1
* @author zzz
*/
public class SHA1Hash extends DataStructureImpl {
private byte[] _data;
private int _cachedHashCode;
public final static int HASH_LENGTH = SHA1.HASH_LENGTH;
/** @throws IllegalArgumentException if data is not 20 bytes (null is ok) */
public SHA1Hash(byte data[]) {
setData(data);
}
public byte[] getData() {
return _data;
}
/** @throws IllegalArgumentException if data is not 20 bytes (null is ok) */
public void setData(byte[] data) {
// FIXME DSAEngine uses a SHA-1 "Hash" as parameters and return values!
if (data != null && data.length != HASH_LENGTH)
throw new IllegalArgumentException("Hash must be 20 bytes");
_data = data;
_cachedHashCode = calcHashCode();
}
/** @throws IOException always */
public void readBytes(InputStream in) throws DataFormatException, IOException {
throw new IOException("unimplemented");
}
/** @throws IOException always */
public void writeBytes(OutputStream out) throws DataFormatException, IOException {
throw new IOException("unimplemented");
}
@Override
public boolean equals(Object obj) {
if ((obj == null) || !(obj instanceof SHA1Hash)) return false;
return DataHelper.eq(_data, ((SHA1Hash) obj)._data);
}
/** a Hash is a hash, so just use the first 4 bytes for speed */
@Override
public int hashCode() {
return _cachedHashCode;
}
/** a Hash is a hash, so just use the first 4 bytes for speed */
private int calcHashCode() {
int rv = 0;
if (_data != null) {
for (int i = 0; i < 4; i++)
rv ^= (_data[i] << (i*8));
}
return rv;
}
}

View File

@ -10,24 +10,22 @@ package net.i2p.crypto;
*/
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import net.i2p.I2PAppContext;
import net.i2p.util.Clock;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource;
/**
* Precalculate the Y and K for ElGamal encryption operations.
*
* This class precalcs a set of values on its own thread, using those transparently
* when a new instance is created. By default, the minimum threshold for creating
* new values for the pool is 5, and the max pool size is 10. Whenever the pool has
* new values for the pool is 20, and the max pool size is 50. Whenever the pool has
* less than the minimum, it fills it up again to the max. There is a delay after
* each precalculation so that the CPU isn't hosed during startup (defaulting to 10 seconds).
* each precalculation so that the CPU isn't hosed during startup.
* These three parameters are controlled by java environmental variables and
* can be adjusted via:
* -Dcrypto.yk.precalc.min=40 -Dcrypto.yk.precalc.max=100 -Dcrypto.yk.precalc.delay=60000
@ -39,51 +37,36 @@ import net.i2p.util.RandomSource;
* @author jrandom
*/
class YKGenerator {
private final static Log _log = new Log(YKGenerator.class);
private static int MIN_NUM_BUILDERS = -1;
private static int MAX_NUM_BUILDERS = -1;
private static int CALC_DELAY = -1;
/* FIXME final type if you are to syncronize FIXME */
private static volatile List _values = new ArrayList(50); // list of BigInteger[] values (y and k)
private static Thread _precalcThread = null;
//private final static Log _log = new Log(YKGenerator.class);
private static final int MIN_NUM_BUILDERS;
private static final int MAX_NUM_BUILDERS;
private static final int CALC_DELAY;
private static final LinkedBlockingQueue<BigInteger[]> _values = new LinkedBlockingQueue(50); // list of BigInteger[] values (y and k)
private static final Thread _precalcThread;
private static final I2PAppContext ctx;
public final static String PROP_YK_PRECALC_MIN = "crypto.yk.precalc.min";
public final static String PROP_YK_PRECALC_MAX = "crypto.yk.precalc.max";
public final static String PROP_YK_PRECALC_DELAY = "crypto.yk.precalc.delay";
public final static String DEFAULT_YK_PRECALC_MIN = "10";
public final static String DEFAULT_YK_PRECALC_MAX = "30";
public final static String DEFAULT_YK_PRECALC_DELAY = "10000";
public final static int DEFAULT_YK_PRECALC_MIN = 20;
public final static int DEFAULT_YK_PRECALC_MAX = 50;
public final static int DEFAULT_YK_PRECALC_DELAY = 200;
/** check every 30 seconds whether we have less than the minimum */
private final static long CHECK_DELAY = 30 * 1000;
private static long CHECK_DELAY = 30 * 1000;
static {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
try {
int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN));
MIN_NUM_BUILDERS = val;
} catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_YK_PRECALC_MIN);
MIN_NUM_BUILDERS = val;
}
try {
int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX));
MAX_NUM_BUILDERS = val;
} catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_YK_PRECALC_MAX);
MAX_NUM_BUILDERS = val;
}
try {
int val = Integer.parseInt(ctx.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY));
CALC_DELAY = val;
} catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_YK_PRECALC_DELAY);
CALC_DELAY = val;
}
ctx = I2PAppContext.getGlobalContext();
MIN_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN);
MAX_NUM_BUILDERS = ctx.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX);
CALC_DELAY = ctx.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY);
if (_log.shouldLog(Log.DEBUG))
_log.debug("ElGamal YK Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
+ CALC_DELAY + ")");
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("ElGamal YK Precalc (minimum: " + MIN_NUM_BUILDERS + " max: " + MAX_NUM_BUILDERS + ", delay: "
// + CALC_DELAY + ")");
ctx.statManager().createRateStat("crypto.YKUsed", "Need a YK from the queue", "Encryption", new long[] { 60*60*1000 });
ctx.statManager().createRateStat("crypto.YKEmpty", "YK queue empty", "Encryption", new long[] { 60*60*1000 });
_precalcThread = new I2PThread(new YKPrecalcRunner(MIN_NUM_BUILDERS, MAX_NUM_BUILDERS));
_precalcThread.setName("YK Precalc");
@ -93,45 +76,36 @@ class YKGenerator {
}
private static final int getSize() {
synchronized (_values) {
return _values.size();
}
return _values.size();
}
private static final int addValues(BigInteger yk[]) {
int sz = 0;
synchronized (_values) {
_values.add(yk);
sz = _values.size();
}
return sz;
/** @return true if successful, false if full */
private static final boolean addValues(BigInteger yk[]) {
return _values.offer(yk);
}
/** @return rv[0] = Y; rv[1] = K */
public static BigInteger[] getNextYK() {
if (true) {
synchronized (_values) {
if (!_values.isEmpty()) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Sufficient precalculated YK values - fetch the existing");
return (BigInteger[]) _values.remove(0);
}
}
}
if (_log.shouldLog(Log.INFO)) _log.info("Insufficient precalculated YK values - create a new one");
ctx.statManager().addRateData("crypto.YKUsed", 1, 0);
BigInteger[] rv = _values.poll();
if (rv != null)
return rv;
ctx.statManager().addRateData("crypto.YKEmpty", 1, 0);
return generateYK();
}
private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02});
/** @return rv[0] = Y; rv[1] = K */
private static final BigInteger[] generateYK() {
NativeBigInteger k = null;
BigInteger y = null;
long t0 = 0;
long t1 = 0;
//long t0 = 0;
//long t1 = 0;
while (k == null) {
t0 = Clock.getInstance().now();
k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, RandomSource.getInstance());
t1 = Clock.getInstance().now();
//t0 = Clock.getInstance().now();
k = new NativeBigInteger(KeyGenerator.PUBKEY_EXPONENT_SIZE, ctx.random());
//t1 = Clock.getInstance().now();
if (BigInteger.ZERO.compareTo(k) == 0) {
k = null;
continue;
@ -139,39 +113,31 @@ class YKGenerator {
BigInteger kPlus2 = k.add(_two);
if (kPlus2.compareTo(CryptoConstants.elgp) > 0) k = null;
}
long t2 = Clock.getInstance().now();
//long t2 = Clock.getInstance().now();
y = CryptoConstants.elgg.modPow(k, CryptoConstants.elgp);
BigInteger yk[] = new BigInteger[2];
yk[0] = y;
yk[1] = k;
long diff = t2 - t0;
if (diff > 1000) {
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to generate YK value for ElGamal (" + diff + "ms)");
}
//long diff = t2 - t0;
//if (diff > 1000) {
// if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to generate YK value for ElGamal (" + diff + "ms)");
//}
return yk;
}
public static void main(String args[]) {
RandomSource.getInstance().nextBoolean(); // warm it up
try {
Thread.sleep(20 * 1000);
} catch (InterruptedException ie) { // nop
}
_log.debug("\n\n\n\nBegin test\n");
System.out.println("\n\n\n\nBegin test\n");
long negTime = 0;
for (int i = 0; i < 5; i++) {
long startNeg = Clock.getInstance().now();
getNextYK();
long endNeg = Clock.getInstance().now();
negTime += endNeg - startNeg;
}
_log.debug("YK fetch time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException ie) { // nop
}
System.out.println("YK fetch time for 5 runs: " + negTime + " @ " + negTime / 5l + "ms each");
}
private static class YKPrecalcRunner implements Runnable {
@ -186,15 +152,21 @@ class YKGenerator {
public void run() {
while (true) {
int curSize = 0;
long start = Clock.getInstance().now();
//long start = Clock.getInstance().now();
int startSize = getSize();
// Adjust delay
if (startSize <= (_minSize / 2) && CHECK_DELAY > 1000)
CHECK_DELAY -= 1000;
else if (startSize > (_minSize * 2) && CHECK_DELAY < 60000)
CHECK_DELAY += 1000;
curSize = startSize;
while (curSize < _minSize) {
while (curSize < _maxSize) {
long begin = Clock.getInstance().now();
curSize = addValues(generateYK());
long end = Clock.getInstance().now();
if (_log.shouldLog(Log.DEBUG)) _log.debug("Precalculated YK value in " + (end - begin) + "ms");
if (curSize < _minSize) {
for (int i = curSize; i < _maxSize; i++) {
//long begin = Clock.getInstance().now();
if (!addValues(generateYK()))
break;
//long end = Clock.getInstance().now();
//if (_log.shouldLog(Log.DEBUG)) _log.debug("Precalculated YK value in " + (end - begin) + "ms");
// for some relief...
try {
Thread.sleep(CALC_DELAY);
@ -202,14 +174,14 @@ class YKGenerator {
}
}
}
long end = Clock.getInstance().now();
int numCalc = curSize - startSize;
if (numCalc > 0) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Precalced " + numCalc + " to " + curSize + " in "
+ (end - start - CALC_DELAY * numCalc) + "ms (not counting "
+ (CALC_DELAY * numCalc) + "ms relief). now sleeping");
}
//long end = Clock.getInstance().now();
//int numCalc = curSize - startSize;
//if (numCalc > 0) {
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Precalced " + numCalc + " to " + curSize + " in "
// + (end - start - CALC_DELAY * numCalc) + "ms (not counting "
// + (CALC_DELAY * numCalc) + "ms relief). now sleeping");
//}
try {
Thread.sleep(CHECK_DELAY);
} catch (InterruptedException ie) { // nop
@ -217,4 +189,4 @@ class YKGenerator {
}
}
}
}
}

View File

@ -17,7 +17,6 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@ -42,6 +41,7 @@ import net.i2p.util.ByteCache;
import net.i2p.util.OrderedProperties;
import net.i2p.util.ReusableGZIPInputStream;
import net.i2p.util.ReusableGZIPOutputStream;
import net.i2p.util.SecureFileOutputStream;
/**
* Defines some simple IO routines for dealing with marshalling data structures
@ -339,11 +339,12 @@ public class DataHelper {
/**
* Writes the props to the file, unsorted (unless props is an OrderedProperties)
* 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.
*/
public static void storeProps(Properties props, File file) throws IOException {
PrintWriter out = null;
try {
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), "UTF-8")));
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(file), "UTF-8")));
out.println("# NOTE: This I2P config file must use UTF-8 encoding");
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
String name = (String)iter.next();

View File

@ -31,6 +31,7 @@ public class Hash extends DataStructureImpl {
public Hash() {
}
/** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */
public Hash(byte data[]) {
setData(data);
}
@ -39,7 +40,10 @@ public class Hash extends DataStructureImpl {
return _data;
}
/** @throws IllegalArgumentException if data is not 32 bytes (null is ok) */
public void setData(byte[] data) {
if (data != null && data.length != HASH_LENGTH)
throw new IllegalArgumentException("Hash must be 32 bytes");
_data = data;
_stringified = null;
_base64ed = null;

View File

@ -14,8 +14,11 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import net.i2p.util.OrderedProperties;
/**
* Defines a method of communicating with a router
*
@ -28,7 +31,7 @@ public class RouterAddress extends DataStructureImpl {
private Properties _options;
public RouterAddress() {
setCost(-1);
_cost = -1;
}
/**
@ -134,18 +137,27 @@ public class RouterAddress extends DataStructureImpl {
return DataHelper.hashCode(_transportStyle);
}
/**
* This is used on peers.jsp so sort options so it looks better.
* We don't just use OrderedProperties for _options because DataHelper.writeProperties()
* sorts also.
*/
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
StringBuilder buf = new StringBuilder(128);
buf.append("[RouterAddress: ");
buf.append("\n\tTransportStyle: ").append(getTransportStyle());
buf.append("\n\tCost: ").append(getCost());
buf.append("\n\tExpiration: ").append(getExpiration());
buf.append("\n\tOptions: #: ").append(getOptions().size());
for (Iterator iter = getOptions().keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
String val = getOptions().getProperty(key);
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
buf.append("\n\tTransportStyle: ").append(_transportStyle);
buf.append("\n\tCost: ").append(_cost);
buf.append("\n\tExpiration: ").append(_expiration);
if (_options != null) {
buf.append("\n\tOptions: #: ").append(_options.size());
Properties p = new OrderedProperties();
p.putAll(_options);
for (Map.Entry e : p.entrySet()) {
String key = (String) e.getKey();
String val = (String) e.getValue();
buf.append("\n\t\t[").append(key).append("] = [").append(val).append("]");
}
}
buf.append("]");
return buf.toString();

View File

@ -49,16 +49,16 @@ public class AbuseReason extends DataStructureImpl {
@Override
public boolean equals(Object object) {
if ((object == null) || !(object instanceof AbuseReason)) return false;
return DataHelper.eq(getReason(), ((AbuseReason) object).getReason());
return DataHelper.eq(_reason, ((AbuseReason) object).getReason());
}
@Override
public int hashCode() {
return DataHelper.hashCode(getReason());
return DataHelper.hashCode(_reason);
}
@Override
public String toString() {
return "[AbuseReason: " + getReason() + "]";
return "[AbuseReason: " + _reason + "]";
}
}

View File

@ -28,7 +28,7 @@ public class AbuseSeverity extends DataStructureImpl {
private int _severityId;
public AbuseSeverity() {
setSeverity(-1);
_severityId = -1;
}
public int getSeverity() {
@ -56,11 +56,11 @@ public class AbuseSeverity extends DataStructureImpl {
@Override
public int hashCode() {
return getSeverity();
return _severityId;
}
@Override
public String toString() {
return "[AbuseSeverity: " + getSeverity() + "]";
return "[AbuseSeverity: " + _severityId + "]";
}
}

View File

@ -27,11 +27,11 @@ public class CreateSessionMessage extends I2CPMessageImpl {
private SessionConfig _sessionConfig;
public CreateSessionMessage(SessionConfig config) {
setSessionConfig(config);
_sessionConfig = config;
}
public CreateSessionMessage() {
setSessionConfig(new SessionConfig());
_sessionConfig = new SessionConfig();
}
public SessionConfig getSessionConfig() {
@ -75,7 +75,7 @@ public class CreateSessionMessage extends I2CPMessageImpl {
public boolean equals(Object object) {
if ((object != null) && (object instanceof CreateSessionMessage)) {
CreateSessionMessage msg = (CreateSessionMessage) object;
return DataHelper.eq(getSessionConfig(), msg.getSessionConfig());
return DataHelper.eq(_sessionConfig, msg.getSessionConfig());
}
return false;
@ -85,7 +85,7 @@ public class CreateSessionMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[CreateSessionMessage: ");
buf.append("\n\tConfig: ").append(getSessionConfig());
buf.append("\n\tConfig: ").append(_sessionConfig);
buf.append("]");
return buf.toString();
}

View File

@ -69,7 +69,7 @@ public class DestroySessionMessage extends I2CPMessageImpl {
public boolean equals(Object object) {
if ((object != null) && (object instanceof DestroySessionMessage)) {
DestroySessionMessage msg = (DestroySessionMessage) object;
return DataHelper.eq(getSessionId(), msg.getSessionId());
return DataHelper.eq(_sessionId, msg.getSessionId());
}
return false;
@ -86,7 +86,7 @@ public class DestroySessionMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[DestroySessionMessage: ");
buf.append("\n\tSessionId: ").append(getSessionId());
buf.append("\n\tSessionId: ").append(_sessionId);
buf.append("]");
return buf.toString();
}

View File

@ -41,7 +41,7 @@ public class I2CPMessageHandler {
try {
if (length < 0) throw new I2CPMessageException("Invalid message length specified");
int type = (int) DataHelper.readLong(in, 1);
I2CPMessage msg = createMessage(in, length, type);
I2CPMessage msg = createMessage(type);
msg.readMessage(in, length, type);
return msg;
} catch (DataFormatException dfe) {
@ -53,8 +53,8 @@ public class I2CPMessageHandler {
* Yes, this is fairly ugly, but its the only place it ever happens.
*
*/
private static I2CPMessage createMessage(InputStream in, int length, int type) throws IOException,
I2CPMessageException {
private static I2CPMessage createMessage(int type) throws IOException,
I2CPMessageException {
switch (type) {
case CreateLeaseSetMessage.MESSAGE_TYPE:
return new CreateLeaseSetMessage();
@ -101,6 +101,7 @@ public class I2CPMessageHandler {
}
}
/***
public static void main(String args[]) {
try {
I2CPMessage msg = readMessage(new FileInputStream(args[0]));
@ -109,4 +110,5 @@ public class I2CPMessageHandler {
e.printStackTrace();
}
}
***/
}

View File

@ -27,10 +27,10 @@ public class MessageId extends DataStructureImpl {
private long _messageId;
public MessageId() {
setMessageId(-1);
_messageId = -1;
}
public MessageId(long id) {
setMessageId(id);
_messageId = id;
}
public long getMessageId() {
@ -58,11 +58,11 @@ public class MessageId extends DataStructureImpl {
@Override
public int hashCode() {
return (int)getMessageId();
return (int)_messageId;
}
@Override
public String toString() {
return "[MessageId: " + getMessageId() + "]";
return "[MessageId: " + _messageId + "]";
}
}

View File

@ -29,8 +29,8 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
private Payload _payload;
public MessagePayloadMessage() {
setSessionId(-1);
setMessageId(-1);
_sessionId = -1;
_messageId = -1;
}
public long getSessionId() {
@ -113,7 +113,7 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
MessagePayloadMessage msg = (MessagePayloadMessage) object;
return _sessionId == msg.getSessionId()
&& _messageId == msg.getMessageId()
&& DataHelper.eq(getPayload(), msg.getPayload());
&& DataHelper.eq(_payload, msg.getPayload());
}
return false;
@ -123,9 +123,9 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[MessagePayloadMessage: ");
buf.append("\n\tSessionId: ").append(getSessionId());
buf.append("\n\tMessageId: ").append(getMessageId());
buf.append("\n\tPayload: ").append(getPayload());
buf.append("\n\tSessionId: ").append(_sessionId);
buf.append("\n\tMessageId: ").append(_messageId);
buf.append("\n\tPayload: ").append(_payload);
buf.append("]");
return buf.toString();
}

View File

@ -32,17 +32,19 @@ public class MessageStatusMessage extends I2CPMessageImpl {
public final static int STATUS_AVAILABLE = 0;
public final static int STATUS_SEND_ACCEPTED = 1;
/** unused */
public final static int STATUS_SEND_BEST_EFFORT_SUCCESS = 2;
/** unused */
public final static int STATUS_SEND_BEST_EFFORT_FAILURE = 3;
public final static int STATUS_SEND_GUARANTEED_SUCCESS = 4;
public final static int STATUS_SEND_GUARANTEED_FAILURE = 5;
public MessageStatusMessage() {
setSessionId(-1);
setStatus(-1);
setMessageId(-1);
setSize(-1);
setNonce(-1);
_sessionId = -1;
_status = -1;
_messageId = -1;
_size = -1;
_nonce = -1;
}
public long getSessionId() {
@ -169,11 +171,11 @@ public class MessageStatusMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[MessageStatusMessage: ");
buf.append("\n\tSessionId: ").append(getSessionId());
buf.append("\n\tNonce: ").append(getNonce());
buf.append("\n\tMessageId: ").append(getMessageId());
buf.append("\n\tStatus: ").append(getStatusString(getStatus()));
buf.append("\n\tSize: ").append(getSize());
buf.append("\n\tSessionId: ").append(_sessionId);
buf.append("\n\tNonce: ").append(_nonce);
buf.append("\n\tMessageId: ").append(_messageId);
buf.append("\n\tStatus: ").append(getStatusString(_status));
buf.append("\n\tSize: ").append(_size);
buf.append("]");
return buf.toString();
}

View File

@ -28,8 +28,8 @@ public class ReceiveMessageBeginMessage extends I2CPMessageImpl {
private long _messageId;
public ReceiveMessageBeginMessage() {
setSessionId(-1);
setMessageId(-1);
_sessionId = -1;
_messageId = -1;
}
public long getSessionId() {
@ -103,8 +103,8 @@ public class ReceiveMessageBeginMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[ReceiveMessageBeginMessage: ");
buf.append("\n\tSessionId: ").append(getSessionId());
buf.append("\n\tMessageId: ").append(getMessageId());
buf.append("\n\tSessionId: ").append(_sessionId);
buf.append("\n\tMessageId: ").append(_messageId);
buf.append("]");
return buf.toString();
}

View File

@ -27,8 +27,8 @@ public class ReceiveMessageEndMessage extends I2CPMessageImpl {
private long _messageId;
public ReceiveMessageEndMessage() {
setSessionId(-1);
setMessageId(-1);
_sessionId = -1;
_messageId = -1;
}
public long getSessionId() {
@ -87,8 +87,8 @@ public class ReceiveMessageEndMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[ReceiveMessageEndMessage: ");
buf.append("\n\tSessionId: ").append(getSessionId());
buf.append("\n\tMessageId: ").append(getMessageId());
buf.append("\n\tSessionId: ").append(_sessionId);
buf.append("\n\tMessageId: ").append(_messageId);
buf.append("]");
return buf.toString();
}

View File

@ -81,8 +81,8 @@ public class ReconfigureSessionMessage extends I2CPMessageImpl {
public boolean equals(Object object) {
if ((object != null) && (object instanceof ReconfigureSessionMessage)) {
ReconfigureSessionMessage msg = (ReconfigureSessionMessage) object;
return DataHelper.eq(getSessionId(), msg.getSessionId())
&& DataHelper.eq(getSessionConfig(), msg.getSessionConfig());
return DataHelper.eq(_sessionId, msg.getSessionId())
&& DataHelper.eq(_sessionConfig, msg.getSessionConfig());
}
return false;
@ -92,8 +92,8 @@ public class ReconfigureSessionMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[ReconfigureSessionMessage: ");
buf.append("\n\tSessionId: ").append(getSessionId());
buf.append("\n\tSessionConfig: ").append(getSessionConfig());
buf.append("\n\tSessionId: ").append(_sessionId);
buf.append("\n\tSessionConfig: ").append(_sessionConfig);
buf.append("]");
return buf.toString();
}

View File

@ -30,7 +30,7 @@ import net.i2p.data.TunnelId;
public class RequestLeaseSetMessage extends I2CPMessageImpl {
public final static int MESSAGE_TYPE = 21;
private SessionId _sessionId;
private List _endpoints;
private List<TunnelEndpoint> _endpoints;
private Date _end;
public RequestLeaseSetMessage() {
@ -51,12 +51,12 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
public Hash getRouter(int endpoint) {
if ((endpoint < 0) || (_endpoints.size() < endpoint)) return null;
return ((TunnelEndpoint) _endpoints.get(endpoint)).getRouter();
return _endpoints.get(endpoint).getRouter();
}
public TunnelId getTunnelId(int endpoint) {
if ((endpoint < 0) || (_endpoints.size() < endpoint)) return null;
return ((TunnelEndpoint) _endpoints.get(endpoint)).getTunnelId();
return _endpoints.get(endpoint).getTunnelId();
}
/** @deprecated unused - presumably he meant remove? */
@ -159,8 +159,6 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
private TunnelId _tunnelId;
public TunnelEndpoint() {
_router = null;
_tunnelId = null;
}
public TunnelEndpoint(Hash router, TunnelId id) {

View File

@ -168,8 +168,8 @@ public class SessionConfig extends DataStructureImpl {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
_log.debug("PubKey size for destination: " + _destination.getPublicKey().getData().length);
_log.debug("SigningKey size for destination: " + _destination.getSigningPublicKey().getData().length);
//_log.debug("PubKey size for destination: " + _destination.getPublicKey().getData().length);
//_log.debug("SigningKey size for destination: " + _destination.getSigningPublicKey().getData().length);
_destination.writeBytes(out);
DataHelper.writeProperties(out, _options, true); // UTF-8
DataHelper.writeDate(out, _creationDate);

View File

@ -26,7 +26,7 @@ public class SessionId extends DataStructureImpl {
private int _sessionId;
public SessionId() {
setSessionId(-1);
_sessionId = -1;
}
public int getSessionId() {
@ -49,16 +49,16 @@ public class SessionId extends DataStructureImpl {
@Override
public boolean equals(Object obj) {
if ((obj == null) || !(obj instanceof SessionId)) return false;
return getSessionId() == ((SessionId) obj).getSessionId();
return _sessionId == ((SessionId) obj).getSessionId();
}
@Override
public int hashCode() {
return getSessionId();
return _sessionId;
}
@Override
public String toString() {
return "[SessionId: " + getSessionId() + "]";
return "[SessionId: " + _sessionId + "]";
}
}

View File

@ -28,7 +28,7 @@ public class SetDateMessage extends I2CPMessageImpl {
public SetDateMessage() {
super();
setDate(new Date(Clock.getInstance().now()));
_date = new Date(Clock.getInstance().now());
}
public Date getDate() {
@ -70,7 +70,7 @@ public class SetDateMessage extends I2CPMessageImpl {
public boolean equals(Object object) {
if ((object != null) && (object instanceof SetDateMessage)) {
SetDateMessage msg = (SetDateMessage) object;
return DataHelper.eq(getDate(), msg.getDate());
return DataHelper.eq(_date, msg.getDate());
}
return false;
@ -80,7 +80,7 @@ public class SetDateMessage extends I2CPMessageImpl {
public String toString() {
StringBuilder buf = new StringBuilder();
buf.append("[SetDateMessage");
buf.append("\n\tDate: ").append(getDate());
buf.append("\n\tDate: ").append(_date);
buf.append("]");
return buf.toString();
}

View File

@ -55,11 +55,11 @@ public class EepGet {
protected long _bytesTransferred;
protected long _bytesRemaining;
protected int _currentAttempt;
private String _etag;
private String _lastModified;
protected String _etag;
protected String _lastModified;
protected boolean _encodingChunked;
protected boolean _notModified;
private String _contentType;
protected String _contentType;
protected boolean _transferFailed;
protected boolean _headersRead;
protected boolean _aborted;
@ -537,6 +537,15 @@ public class EepGet {
if (_redirects > 5)
throw new IOException("Too many redirects: to " + _redirectLocation);
if (_log.shouldLog(Log.INFO)) _log.info("Redirecting to " + _redirectLocation);
// reset some important variables, we don't want to save the values from the redirect
_bytesRemaining = -1;
_redirectLocation = null;
_etag = null;
_lastModified = null;
_contentType = null;
_encodingChunked = false;
sendRequest(timeout);
doFetch(timeout);
return;

View File

@ -116,6 +116,7 @@ public class EepHead extends EepGet {
else
timeout.setInactivityTimeout(60*1000);
// Should we even follow redirects for HEAD?
if (_redirectLocation != null) {
//try {
URL oldURL = new URL(_actualURL);
@ -143,6 +144,15 @@ public class EepHead extends EepGet {
if (_redirects > 5)
throw new IOException("Too many redirects: to " + _redirectLocation);
if (_log.shouldLog(Log.INFO)) _log.info("Redirecting to " + _redirectLocation);
// reset some important variables, we don't want to save the values from the redirect
_bytesRemaining = -1;
_redirectLocation = null;
_etag = null;
_lastModified = null;
_contentType = null;
_encodingChunked = false;
sendRequest(timeout);
doFetch(timeout);
return;

View File

@ -11,8 +11,8 @@ import net.i2p.I2PAppContext;
*/
public class LogConsoleBuffer {
private I2PAppContext _context;
private final List _buffer;
private final List _critBuffer;
private final List<String> _buffer;
private final List<String> _critBuffer;
public LogConsoleBuffer(I2PAppContext context) {
_context = context;
@ -43,7 +43,7 @@ public class LogConsoleBuffer {
* in the logs)
*
*/
public List getMostRecentMessages() {
public List<String> getMostRecentMessages() {
synchronized (_buffer) {
return new ArrayList(_buffer);
}
@ -54,9 +54,9 @@ public class LogConsoleBuffer {
* in the logs)
*
*/
public List getMostRecentCriticalMessages() {
public List<String> getMostRecentCriticalMessages() {
synchronized (_critBuffer) {
return new ArrayList(_critBuffer);
}
}
}
}

View File

@ -156,7 +156,7 @@ public class LogManager {
return rv;
}
/** @deprecated unused */
/** now used by ConfigLogingHelper */
public List<Log> getLogs() {
return new ArrayList(_logs.values());
}
@ -415,15 +415,21 @@ public class LogManager {
/**
* Determine how many bytes are in the given formatted string (5m, 60g, 100k, etc)
*
* Size may be k, m, or g; a trailing b is ignored. Upper-case is allowed.
* Spaces between the number and letter is are allowed.
* The number may be in floating point.
* 4096 min, 2 GB max (returns int)
*/
public int getFileSize(String size) {
int sz = -1;
public static int getFileSize(String size) {
try {
String v = size;
char mod = size.toUpperCase().charAt(size.length() - 1);
if (!Character.isDigit(mod)) v = size.substring(0, size.length() - 1);
int val = Integer.parseInt(v);
String v = size.trim().toUpperCase();
if (v.length() < 2)
return -1;
if (v.endsWith("B"))
v = v.substring(0, v.length() - 1);
char mod = v.charAt(v.length() - 1);
if (!Character.isDigit(mod)) v = v.substring(0, v.length() - 1);
double val = Double.parseDouble(v);
switch (mod) {
case 'K':
val *= 1024;
@ -438,10 +444,11 @@ public class LogManager {
// blah, noop
break;
}
return val;
if (val < 4096 || val > Integer.MAX_VALUE)
return -1;
return (int) val;
} catch (Throwable t) {
System.err.println("Error parsing config for filesize: [" + size + "]");
t.printStackTrace();
return -1;
}
}

View File

@ -11,7 +11,6 @@ package net.i2p.util;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@ -158,7 +157,8 @@ class LogWriter implements Runnable {
File parent = f.getParentFile();
if (parent != null) {
if (!parent.exists()) {
boolean ok = parent.mkdirs();
File sd = new SecureDirectory(parent.getAbsolutePath());
boolean ok = sd.mkdirs();
if (!ok) {
System.err.println("Unable to create the parent directory: " + parent.getAbsolutePath());
//System.exit(0);
@ -171,7 +171,7 @@ class LogWriter implements Runnable {
}
closeFile();
try {
_currentOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
_currentOut = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(f), "UTF-8"));
} catch (IOException ioe) {
System.err.println("Error rotating into [" + f.getAbsolutePath() + "]" + ioe);
}

View File

@ -145,7 +145,7 @@ public class RandomSource extends SecureRandom implements EntropyHarvester {
File f = new File(I2PAppContext.getGlobalContext().getConfigDir(), SEEDFILE);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
fos = new SecureFileOutputStream(f);
fos.write(buf);
} catch (IOException ioe) {
// ignore

View File

@ -0,0 +1,74 @@
package net.i2p.util;
import java.io.File;
/**
* Same as File but sets the file mode after mkdir() so it can
* be read and written by the owner only (i.e. 700 on linux)
*
* @since 0.8.1
* @author zzz
*/
public class SecureDirectory extends File {
private static final boolean canSetPerms =
(new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0;
private static final boolean isNotWindows = !System.getProperty("os.name").startsWith("Win");
public SecureDirectory(String pathname) {
super(pathname);
}
public SecureDirectory(String parent, String child) {
super(parent, child);
}
public SecureDirectory(File parent, String child) {
super(parent, child);
}
/**
* Sets directory to mode 700 if the directory is created
*/
@Override
public boolean mkdir() {
boolean rv = super.mkdir();
if (rv)
setPerms();
return rv;
}
/**
* Sets directory to mode 700 if the directory is created
* Does NOT change the mode of other created directories
*/
@Override
public boolean mkdirs() {
boolean rv = super.mkdirs();
if (rv)
setPerms();
return rv;
}
/**
* Tries to set the permissions to 700,
* ignores errors
*/
private void setPerms() {
if (!canSetPerms)
return;
try {
setReadable(false, false);
setReadable(true, true);
setWritable(false, false);
setWritable(true, true);
if (isNotWindows) {
setExecutable(false, false);
setExecutable(true, true);
}
} catch (Throwable t) {
// NoSuchMethodException or NoSuchMethodError if we somehow got the
// version detection wrong or the JVM doesn't support it
}
}
}

View File

@ -0,0 +1,72 @@
package net.i2p.util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
/**
* Same as FileOutputStream but sets the file mode so it can only
* be read and written by the owner only (i.e. 600 on linux)
*
* @since 0.8.1
* @author zzz
*/
public class SecureFileOutputStream extends FileOutputStream {
private static final boolean canSetPerms =
(new VersionComparator()).compare(System.getProperty("java.version"), "1.6") >= 0;
/**
* Sets output file to mode 600
*/
public SecureFileOutputStream(String file) throws FileNotFoundException {
super(file);
setPerms(new File(file));
}
/**
* Sets output file to mode 600 only if append = false
* (otherwise it is presumed to be 600 already)
*/
public SecureFileOutputStream(String file, boolean append) throws FileNotFoundException {
super(file, append);
//if (!append)
setPerms(new File(file));
}
/**
* Sets output file to mode 600
*/
public SecureFileOutputStream(File file) throws FileNotFoundException {
super(file);
setPerms(file);
}
/**
* Sets output file to mode 600 only if append = false
* (otherwise it is presumed to be 600 already)
*/
public SecureFileOutputStream(File file, boolean append) throws FileNotFoundException {
super(file, append);
//if (!append)
setPerms(file);
}
/**
* Tries to set the permissions to 600,
* ignores errors
*/
private static void setPerms(File f) {
if (!canSetPerms)
return;
try {
f.setReadable(false, false);
f.setReadable(true, true);
f.setWritable(false, false);
f.setWritable(true, true);
} catch (Throwable t) {
// NoSuchMethodException or NoSuchMethodError if we somehow got the
// version detection wrong or the JVM doesn't support it
}
}
}