diff --git a/apps/httptunnel/java/src/net/i2p/httptunnel/HTTPListener.java b/apps/httptunnel/java/src/net/i2p/httptunnel/HTTPListener.java index d613f6033..60f6752c8 100644 --- a/apps/httptunnel/java/src/net/i2p/httptunnel/HTTPListener.java +++ b/apps/httptunnel/java/src/net/i2p/httptunnel/HTTPListener.java @@ -53,7 +53,7 @@ public class HTTPListener extends Thread { private boolean proxyUsed = false; /** - * Query whether this is the first use of the proxy or not . . . + * Query whether this is the first use of the proxy or not * @return Whether this is the first proxy use, no doubt. */ public boolean firstProxyUse() { diff --git a/apps/httptunnel/java/src/net/i2p/httptunnel/handler/EepHandler.java b/apps/httptunnel/java/src/net/i2p/httptunnel/handler/EepHandler.java index 1535d2915..9e5d105f9 100644 --- a/apps/httptunnel/java/src/net/i2p/httptunnel/handler/EepHandler.java +++ b/apps/httptunnel/java/src/net/i2p/httptunnel/handler/EepHandler.java @@ -19,6 +19,7 @@ import net.i2p.httptunnel.SocketManagerProducer; import net.i2p.httptunnel.filter.Filter; import net.i2p.httptunnel.filter.NullFilter; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Handler for browsing Eepsites. @@ -26,6 +27,7 @@ import net.i2p.util.Log; public class EepHandler { private static final Log _log = new Log(EepHandler.class); + private static I2PAppContext _context = new I2PAppContext(); protected ErrorHandler errorHandler; @@ -44,7 +46,7 @@ public class EepHandler { public void handle(Request req, HTTPListener httpl, OutputStream out, /* boolean fromProxy, */String destination) throws IOException { SocketManagerProducer smp = httpl.getSMP(); - Destination dest = NamingService.getInstance().lookup(destination); + Destination dest = _context.namingService().lookup(destination); if (dest == null) { errorHandler.handle(req, httpl, out, "Could not lookup host: " + destination); return; @@ -66,8 +68,8 @@ public class EepHandler { * @return boolean, true if something was written, false otherwise. * @throws IOException */ - public boolean handle(Request req, Filter f, OutputStream out, Destination dest, I2PSocketManager sm) - throws IOException { + public boolean handle(Request req, Filter f, OutputStream out, Destination dest, + I2PSocketManager sm) throws IOException { I2PSocket s = null; boolean written = false; try { diff --git a/apps/httptunnel/java/src/net/i2p/httptunnel/handler/ProxyHandler.java b/apps/httptunnel/java/src/net/i2p/httptunnel/handler/ProxyHandler.java index 02f454d49..da0b856b7 100644 --- a/apps/httptunnel/java/src/net/i2p/httptunnel/handler/ProxyHandler.java +++ b/apps/httptunnel/java/src/net/i2p/httptunnel/handler/ProxyHandler.java @@ -12,6 +12,7 @@ import net.i2p.httptunnel.SocketManagerProducer; import net.i2p.httptunnel.filter.Filter; import net.i2p.httptunnel.filter.NullFilter; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Handler for proxying "normal" HTTP requests. @@ -19,6 +20,7 @@ import net.i2p.util.Log; public class ProxyHandler extends EepHandler { private static final Log _log = new Log(ErrorHandler.class); + private static I2PAppContext _context = new I2PAppContext(); /* package private */ProxyHandler(ErrorHandler eh) { super(eh); @@ -31,7 +33,7 @@ public class ProxyHandler extends EepHandler { * @throws IOException */ public void handle(Request req, HTTPListener httpl, OutputStream out - /*, boolean fromProxy */) throws IOException { + /*, boolean fromProxy */) throws IOException { SocketManagerProducer smp = httpl.getSMP(); Destination dest = findProxy(); if (dest == null) { @@ -48,6 +50,6 @@ public class ProxyHandler extends EepHandler { private Destination findProxy() { //FIXME! - return NamingService.getInstance().lookup("squid.i2p"); + return _context.namingService().lookup("squid.i2p"); } } \ No newline at end of file diff --git a/apps/httptunnel/java/src/net/i2p/httptunnel/handler/RootHandler.java b/apps/httptunnel/java/src/net/i2p/httptunnel/handler/RootHandler.java index d40f14c0f..4f94d4744 100644 --- a/apps/httptunnel/java/src/net/i2p/httptunnel/handler/RootHandler.java +++ b/apps/httptunnel/java/src/net/i2p/httptunnel/handler/RootHandler.java @@ -29,7 +29,7 @@ public class RootHandler { private static RootHandler instance; /** - * Singleton stuff . . . + * Singleton stuff * @return the one and only instance, yay! */ public static synchronized RootHandler getInstance() { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 93fb64121..dcf28d1e1 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -49,6 +49,7 @@ import java.util.List; import java.util.Set; import java.util.StringTokenizer; +import net.i2p.I2PAppContext; import net.i2p.I2PException; import net.i2p.client.I2PClient; import net.i2p.client.I2PClientFactory; @@ -65,6 +66,7 @@ import net.i2p.util.Log; public class I2PTunnel implements Logging, EventDispatcher { private final static Log _log = new Log(I2PTunnel.class); private final EventDispatcherImpl _event = new EventDispatcherImpl(); + private static I2PAppContext _context = new I2PAppContext(); public static final int PACKET_DELAY = 100; @@ -954,7 +956,7 @@ public class I2PTunnel implements Logging, EventDispatcher { } } else { // ask naming service - NamingService inst = NamingService.getInstance(); + NamingService inst = _context.namingService(); return inst.lookup(name); } } diff --git a/apps/sam/java/src/net/i2p/sam/SAMUtils.java b/apps/sam/java/src/net/i2p/sam/SAMUtils.java index f4ef4ff84..09dce27f3 100644 --- a/apps/sam/java/src/net/i2p/sam/SAMUtils.java +++ b/apps/sam/java/src/net/i2p/sam/SAMUtils.java @@ -23,6 +23,7 @@ import net.i2p.data.Base64; import net.i2p.data.DataFormatException; import net.i2p.data.Destination; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Miscellaneous utility methods used by SAM protocol handlers. @@ -32,6 +33,7 @@ import net.i2p.util.Log; public class SAMUtils { private final static Log _log = new Log(SAMUtils.class); + private static I2PAppContext _context = new I2PAppContext(); /** * Generate a random destination key @@ -84,7 +86,7 @@ public class SAMUtils { * @return the Destination for the specified hostname, or null if not found */ public static Destination lookupHost(String name, OutputStream pubKey) { - NamingService ns = NamingService.getInstance(); + NamingService ns = _context.namingService(); Destination dest = ns.lookup(name); if ((pubKey != null) && (dest != null)) { diff --git a/core/java/src/net/i2p/I2PAppContext.java b/core/java/src/net/i2p/I2PAppContext.java new file mode 100644 index 000000000..7f5bc203e --- /dev/null +++ b/core/java/src/net/i2p/I2PAppContext.java @@ -0,0 +1,425 @@ +package net.i2p; + +import net.i2p.stat.StatManager; +import net.i2p.crypto.SessionKeyManager; +import net.i2p.crypto.PersistentSessionKeyManager; +import net.i2p.crypto.ElGamalAESEngine; +import net.i2p.crypto.ElGamalEngine; +import net.i2p.crypto.DummyElGamalEngine; +import net.i2p.crypto.SHA256Generator; +import net.i2p.crypto.HMACSHA256Generator; +import net.i2p.crypto.AESEngine; +import net.i2p.crypto.CryptixAESEngine; +import net.i2p.crypto.DSAEngine; +import net.i2p.client.naming.NamingService; +import net.i2p.util.LogManager; +import net.i2p.util.Clock; +import net.i2p.util.RandomSource; +import net.i2p.data.RoutingKeyGenerator; +import net.i2p.crypto.KeyGenerator; + +import java.util.Properties; +import java.util.HashSet; +import java.util.Set; + +/** + *

Provide a base scope for accessing singletons that I2P exposes. Rather than + * using the traditional singleton, where any component can access the component + * in question directly, all of those I2P related singletons are exposed through + * a particular I2PAppContext. This helps not only with understanding their use + * and the components I2P exposes, but it also allows multiple isolated + * environments to operate concurrently within the same JVM - particularly useful + * for stubbing out implementations of the rooted components and simulating the + * software's interaction between multiple instances.

+ * + * As a simplification, there is also a global context - if some component needs + * access to one of the singletons but doesn't have its own context from which + * to root itself, it binds to the I2PAppContext's globalAppContext(), which is + * the first context that was created within the JVM, or a new one if no context + * existed already. This functionality is often used within the I2P core for + * logging - e.g.
+ *     private static final Log _log = new Log(someClass.class);
+ * 
+ * It is for this reason that applications that care about working with multiple + * contexts should build their own context as soon as possible (within the main(..)) + * so that any referenced components will latch on to that context instead of + * instantiating a new one. However, there are situations in which both can be + * relevent. + * + */ +public class I2PAppContext { + /** the context that components without explicit root are bound */ + protected static I2PAppContext _globalAppContext; + /** + * Determine if the app context been initialized. If this is false + * and something asks for the globalAppContext, a new one is created, + * otherwise the existing one is used. + * + */ + protected static volatile boolean _globalAppContextInitialized; + + private StatManager _statManager; + private SessionKeyManager _sessionKeyManager; + private NamingService _namingService; + private ElGamalEngine _elGamalEngine; + private ElGamalAESEngine _elGamalAESEngine; + private AESEngine _AESEngine; + private LogManager _logManager; + private HMACSHA256Generator _hmac; + private SHA256Generator _sha; + private Clock _clock; + private DSAEngine _dsa; + private RoutingKeyGenerator _routingKeyGenerator; + private RandomSource _random; + private KeyGenerator _keyGenerator; + private volatile boolean _statManagerInitialized; + private volatile boolean _sessionKeyManagerInitialized; + private volatile boolean _namingServiceInitialized; + private volatile boolean _elGamalEngineInitialized; + private volatile boolean _elGamalAESEngineInitialized; + private volatile boolean _AESEngineInitialized; + private volatile boolean _logManagerInitialized; + private volatile boolean _hmacInitialized; + private volatile boolean _shaInitialized; + private volatile boolean _clockInitialized; + private volatile boolean _dsaInitialized; + private volatile boolean _routingKeyGeneratorInitialized; + private volatile boolean _randomInitialized; + private volatile boolean _keyGeneratorInitialized; + + /** + * Pull the default context, creating a new one if necessary, else using + * the first one created. + * + */ + public static I2PAppContext getGlobalContext() { + if (!_globalAppContextInitialized) { + synchronized (I2PAppContext.class) { + System.err.println("*** Building seperate global context!"); + if (_globalAppContext == null) + _globalAppContext = new I2PAppContext(false); + _globalAppContextInitialized = true; + } + } + return _globalAppContext; + } + + /** + * Lets root a brand new context + * + */ + public I2PAppContext() { + this(true); + } + /** + * @param doInit should this context be used as the global one (if necessary)? + */ + private I2PAppContext(boolean doInit) { + //System.out.println("App context created: " + this); + if (doInit) { + if (!_globalAppContextInitialized) { + synchronized (I2PAppContext.class) { + if (_globalAppContext == null) { + _globalAppContext = this; + _globalAppContextInitialized = true; + } + } + } + } + _statManager = null; + _sessionKeyManager = null; + _namingService = null; + _elGamalEngine = null; + _elGamalAESEngine = null; + _logManager = null; + _statManagerInitialized = false; + _sessionKeyManagerInitialized = false; + _namingServiceInitialized = false; + _elGamalEngineInitialized = false; + _elGamalAESEngineInitialized = false; + _logManagerInitialized = false; + } + + /** + * Access the configuration attributes of this context (aka System.getProperty) + * This can be overloaded by subclasses to allow different system + * properties for different app contexts. + * + */ + public String getProperty(String propName) { + return System.getProperty(propName); + } + /** + * Access the configuration attributes of this context (aka System.getProperty) + * This can be overloaded by subclasses to allow different system + * properties for different app contexts. + * + */ + public String getProperty(String propName, String defaultValue) { + return System.getProperty(propName, defaultValue); + } + /** + * Access the configuration attributes of this context (aka System.getProperties) + * This can be overloaded by subclasses to allow different system + * properties for different app contexts. + * + * @return set of Strings containing the names of defined system properties + */ + public Set getPropertyNames() { + return new HashSet(System.getProperties().keySet()); + } + + /** + * The statistics component with which we can track various events + * over time. + */ + public StatManager statManager() { + if (!_statManagerInitialized) initializeStatManager(); + return _statManager; + } + private void initializeStatManager() { + synchronized (this) { + if (_statManager == null) + _statManager = new StatManager(this); + _statManagerInitialized = true; + } + } + + /** + * The session key manager which coordinates the sessionKey / sessionTag + * data. This component allows transparent operation of the + * ElGamal/AES+SessionTag algorithm, and contains all of the session tags + * for one particular application. If you want to seperate multiple apps + * to have their own sessionTags and sessionKeys, they should use different + * I2PAppContexts, and hence, different sessionKeyManagers. + * + */ + public SessionKeyManager sessionKeyManager() { + if (!_sessionKeyManagerInitialized) initializeSessionKeyManager(); + return _sessionKeyManager; + } + private void initializeSessionKeyManager() { + synchronized (this) { + if (_sessionKeyManager == null) + _sessionKeyManager = new PersistentSessionKeyManager(this); + _sessionKeyManagerInitialized = true; + } + } + + /** + * Pull up the naming service used in this context. The naming service itself + * works by querying the context's properties, so those props should be + * specified to customize the naming service exposed. + */ + public NamingService namingService() { + if (!_namingServiceInitialized) initializeNamingService(); + return _namingService; + } + private void initializeNamingService() { + synchronized (this) { + if (_namingService == null) { + _namingService = NamingService.createInstance(this); + } + _namingServiceInitialized = true; + } + } + + /** + * This is the ElGamal engine used within this context. While it doesn't + * really have anything substantial that is context specific (the algorithm + * just does the algorithm), it does transparently use the context for logging + * its performance and activity. In addition, the engine can be swapped with + * the context's properties (though only someone really crazy should mess with + * it ;) + */ + public ElGamalEngine elGamalEngine() { + if (!_elGamalEngineInitialized) initializeElGamalEngine(); + return _elGamalEngine; + } + private void initializeElGamalEngine() { + synchronized (this) { + if (_elGamalEngine == null) { + if ("off".equals(getProperty("i2p.encryption", "on"))) + _elGamalEngine = new DummyElGamalEngine(this); + else + _elGamalEngine = new ElGamalEngine(this); + } + _elGamalEngineInitialized = true; + } + } + + /** + * Access the ElGamal/AES+SessionTag engine for this context. The algorithm + * makes use of the context's sessionKeyManager to coordinate transparent + * access to the sessionKeys and sessionTags, as well as the context's elGamal + * engine (which in turn keeps stats, etc). + * + */ + public ElGamalAESEngine elGamalAESEngine() { + if (!_elGamalAESEngineInitialized) initializeElGamalAESEngine(); + return _elGamalAESEngine; + } + private void initializeElGamalAESEngine() { + synchronized (this) { + if (_elGamalAESEngine == null) + _elGamalAESEngine = new ElGamalAESEngine(this); + _elGamalAESEngineInitialized = true; + } + } + + /** + * Ok, I'll admit it. there is no good reason for having a context specific + * AES engine. We dont really keep stats on it, since its just too fast to + * matter. Though for the crazy people out there, we do expose a way to + * disable it. + */ + public AESEngine AESEngine() { + if (!_AESEngineInitialized) initializeAESEngine(); + return _AESEngine; + } + private void initializeAESEngine() { + synchronized (this) { + if (_AESEngine == null) { + if ("off".equals(getProperty("i2p.encryption", "on"))) + _AESEngine = new AESEngine(this); + else + _AESEngine = new CryptixAESEngine(this); + } + _AESEngineInitialized = true; + } + } + + /** + * Query the log manager for this context, which may in turn have its own + * set of configuration settings (loaded from the context's properties). + * Each context's logManager keeps its own isolated set of Log instances with + * their own log levels, output locations, and rotation configuration. + */ + public LogManager logManager() { + if (!_logManagerInitialized) initializeLogManager(); + return _logManager; + } + private void initializeLogManager() { + synchronized (this) { + if (_logManager == null) + _logManager = new LogManager(this); + _logManagerInitialized = true; + } + } + /** + * There is absolutely no good reason to make this context specific, + * other than for consistency, and perhaps later we'll want to + * include some stats. + */ + public HMACSHA256Generator hmac() { + if (!_hmacInitialized) initializeHMAC(); + return _hmac; + } + private void initializeHMAC() { + synchronized (this) { + if (_hmac == null) + _hmac= new HMACSHA256Generator(this); + _hmacInitialized = true; + } + } + + /** + * Our SHA256 instance (see the hmac discussion for why its context specific) + * + */ + public SHA256Generator sha() { + if (!_shaInitialized) initializeSHA(); + return _sha; + } + private void initializeSHA() { + synchronized (this) { + if (_sha == null) + _sha= new SHA256Generator(this); + _shaInitialized = true; + } + } + + /** + * Our DSA engine (see HMAC and SHA above) + * + */ + public DSAEngine dsa() { + if (!_dsaInitialized) initializeDSA(); + return _dsa; + } + private void initializeDSA() { + synchronized (this) { + if (_dsa == null) + _dsa = new DSAEngine(this); + _dsaInitialized = true; + } + } + + /** + * Component to generate ElGamal, DSA, and Session keys. For why it is in + * the appContext, see the DSA, HMAC, and SHA comments above. + */ + public KeyGenerator keyGenerator() { + if (!_keyGeneratorInitialized) initializeKeyGenerator(); + return _keyGenerator; + } + private void initializeKeyGenerator() { + synchronized (this) { + if (_keyGenerator == null) + _keyGenerator = new KeyGenerator(this); + _keyGeneratorInitialized = true; + } + } + + /** + * The context's synchronized clock, which is kept context specific only to + * enable simulators to play with clock skew among different instances. + * + */ + public Clock clock() { + if (!_clockInitialized) initializeClock(); + return _clock; + } + private void initializeClock() { + synchronized (this) { + if (_clock == null) + _clock = new Clock(this); + _clockInitialized = true; + } + } + + /** + * Determine how much do we want to mess with the keys to turn them + * into something we can route. This is context specific because we + * may want to test out how things react when peers don't agree on + * how to skew. + * + */ + public RoutingKeyGenerator routingKeyGenerator() { + if (!_routingKeyGeneratorInitialized) initializeRoutingKeyGenerator(); + return _routingKeyGenerator; + } + private void initializeRoutingKeyGenerator() { + synchronized (this) { + if (_routingKeyGenerator == null) + _routingKeyGenerator = new RoutingKeyGenerator(this); + _routingKeyGeneratorInitialized = true; + } + } + + /** + * [insert snarky comment here] + * + */ + public RandomSource random() { + if (!_randomInitialized) initializeRandom(); + return _random; + } + private void initializeRandom() { + synchronized (this) { + if (_random == null) + _random = new RandomSource(this); + _randomInitialized = true; + } + } +} \ No newline at end of file diff --git a/core/java/src/net/i2p/client/ATalk.java b/core/java/src/net/i2p/client/ATalk.java index 53fc937e4..a922c2b9f 100644 --- a/core/java/src/net/i2p/client/ATalk.java +++ b/core/java/src/net/i2p/client/ATalk.java @@ -31,6 +31,7 @@ import net.i2p.util.Clock; import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.LogManager; +import net.i2p.I2PAppContext; /** * ATalk - anonymous talk, demonstrating a trivial I2P usage scenario. @@ -290,6 +291,7 @@ public class ATalk implements I2PSessionListener, Runnable { /** driver */ public static void main(String args[]) { + I2PAppContext context = new I2PAppContext(); if (args.length == 2) { String myKeyFile = args[0]; String myDestinationFile = args[1]; @@ -309,9 +311,9 @@ public class ATalk implements I2PSessionListener, Runnable { String peerDestFile = args[1]; String shouldLog = args[2]; if (Boolean.TRUE.toString().equalsIgnoreCase(shouldLog)) - LogManager.getInstance().setDisplayOnScreen(true); + context.logManager().setDisplayOnScreen(true); else - LogManager.getInstance().setDisplayOnScreen(false); + context.logManager().setDisplayOnScreen(false); String logFile = args[2]; Thread talkThread = new I2PThread(new ATalk(myKeyfile, peerDestFile)); talkThread.start(); diff --git a/core/java/src/net/i2p/client/DisconnectMessageHandler.java b/core/java/src/net/i2p/client/DisconnectMessageHandler.java index 004128bb0..0c1e69d0f 100644 --- a/core/java/src/net/i2p/client/DisconnectMessageHandler.java +++ b/core/java/src/net/i2p/client/DisconnectMessageHandler.java @@ -11,6 +11,7 @@ package net.i2p.client; import net.i2p.data.i2cp.DisconnectMessage; import net.i2p.data.i2cp.I2CPMessage; +import net.i2p.I2PAppContext; /** * Handle I2CP disconnect messages from the router @@ -18,8 +19,8 @@ import net.i2p.data.i2cp.I2CPMessage; * @author jrandom */ class DisconnectMessageHandler extends HandlerImpl { - public DisconnectMessageHandler() { - super(DisconnectMessage.MESSAGE_TYPE); + public DisconnectMessageHandler(I2PAppContext context) { + super(context, DisconnectMessage.MESSAGE_TYPE); } public void handleMessage(I2CPMessage message, I2PSessionImpl session) { diff --git a/core/java/src/net/i2p/client/HandlerImpl.java b/core/java/src/net/i2p/client/HandlerImpl.java index 0337f0dad..bf9171284 100644 --- a/core/java/src/net/i2p/client/HandlerImpl.java +++ b/core/java/src/net/i2p/client/HandlerImpl.java @@ -10,6 +10,7 @@ package net.i2p.client; */ import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Base class for handling I2CP messages @@ -19,8 +20,10 @@ import net.i2p.util.Log; abstract class HandlerImpl implements I2CPMessageHandler { protected Log _log; private int _type; + protected I2PAppContext _context; - public HandlerImpl(int type) { + public HandlerImpl(I2PAppContext context, int type) { + _context = context; _type = type; _log = new Log(getClass()); } diff --git a/core/java/src/net/i2p/client/I2CPMessageProducer.java b/core/java/src/net/i2p/client/I2CPMessageProducer.java index a6432f601..a664d3062 100644 --- a/core/java/src/net/i2p/client/I2CPMessageProducer.java +++ b/core/java/src/net/i2p/client/I2CPMessageProducer.java @@ -32,6 +32,7 @@ import net.i2p.data.i2cp.SendMessageMessage; import net.i2p.data.i2cp.SessionConfig; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Produce the various messages the session needs to send to the router. @@ -41,7 +42,12 @@ import net.i2p.util.RandomSource; class I2CPMessageProducer { private final static Log _log = new Log(I2CPMessageProducer.class); private final static RandomSource _rand = RandomSource.getInstance(); + private I2PAppContext _context; + public I2CPMessageProducer(I2PAppContext context) { + _context = context; + } + /** * Send all the messages that a client needs to send to a router to establish * a new session. @@ -102,7 +108,7 @@ class I2CPMessageProducer { Payload data = new Payload(); // randomize padding int size = payload.length + RandomSource.getInstance().nextInt(1024); - byte encr[] = ElGamalAESEngine.encrypt(payload, dest.getPublicKey(), key, tags, tag, newKey, size); + byte encr[] = _context.elGamalAESEngine().encrypt(payload, dest.getPublicKey(), key, tags, tag, newKey, size); // yes, in an intelligent component, newTags would be queued for confirmation along with key, and // generateNewTags would only generate tags if necessary diff --git a/core/java/src/net/i2p/client/I2PClientImpl.java b/core/java/src/net/i2p/client/I2PClientImpl.java index 1771f0cfe..76dab5a7b 100644 --- a/core/java/src/net/i2p/client/I2PClientImpl.java +++ b/core/java/src/net/i2p/client/I2PClientImpl.java @@ -22,6 +22,7 @@ import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; +import net.i2p.I2PAppContext; /** * Base client implementation @@ -70,7 +71,13 @@ class I2PClientImpl implements I2PClient { * */ public I2PSession createSession(InputStream destKeyStream, Properties options) throws I2PSessionException { - //return new I2PSessionImpl(destKeyStream, options); // not thread safe - return new I2PSessionImpl2(destKeyStream, options); // thread safe + return createSession(I2PAppContext.getGlobalContext(), destKeyStream, options); + } + /** + * Create a new session (though do not connect it yet) + * + */ + public I2PSession createSession(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException { + return new I2PSessionImpl2(context, destKeyStream, options); // thread safe } } \ No newline at end of file diff --git a/core/java/src/net/i2p/client/I2PClientMessageHandlerMap.java b/core/java/src/net/i2p/client/I2PClientMessageHandlerMap.java index 61d0db159..0945999d8 100644 --- a/core/java/src/net/i2p/client/I2PClientMessageHandlerMap.java +++ b/core/java/src/net/i2p/client/I2PClientMessageHandlerMap.java @@ -19,6 +19,7 @@ import net.i2p.data.i2cp.RequestLeaseSetMessage; import net.i2p.data.i2cp.SessionStatusMessage; import net.i2p.data.i2cp.SetDateMessage; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Contains a map of message handlers that a session will want to use @@ -28,19 +29,19 @@ import net.i2p.util.Log; class I2PClientMessageHandlerMap { private final static Log _log = new Log(I2PClientMessageHandlerMap.class); /** map of message type id --> I2CPMessageHandler */ - private static Map _handlers; + private Map _handlers; - static { + public I2PClientMessageHandlerMap(I2PAppContext context) { _handlers = new HashMap(); - _handlers.put(new Integer(DisconnectMessage.MESSAGE_TYPE), new DisconnectMessageHandler()); - _handlers.put(new Integer(SessionStatusMessage.MESSAGE_TYPE), new SessionStatusMessageHandler()); - _handlers.put(new Integer(RequestLeaseSetMessage.MESSAGE_TYPE), new RequestLeaseSetMessageHandler()); - _handlers.put(new Integer(MessagePayloadMessage.MESSAGE_TYPE), new MessagePayloadMessageHandler()); - _handlers.put(new Integer(MessageStatusMessage.MESSAGE_TYPE), new MessageStatusMessageHandler()); - _handlers.put(new Integer(SetDateMessage.MESSAGE_TYPE), new SetDateMessageHandler()); + _handlers.put(new Integer(DisconnectMessage.MESSAGE_TYPE), new DisconnectMessageHandler(context)); + _handlers.put(new Integer(SessionStatusMessage.MESSAGE_TYPE), new SessionStatusMessageHandler(context)); + _handlers.put(new Integer(RequestLeaseSetMessage.MESSAGE_TYPE), new RequestLeaseSetMessageHandler(context)); + _handlers.put(new Integer(MessagePayloadMessage.MESSAGE_TYPE), new MessagePayloadMessageHandler(context)); + _handlers.put(new Integer(MessageStatusMessage.MESSAGE_TYPE), new MessageStatusMessageHandler(context)); + _handlers.put(new Integer(SetDateMessage.MESSAGE_TYPE), new SetDateMessageHandler(context)); } - public static I2CPMessageHandler getHandler(int messageTypeId) { + public I2CPMessageHandler getHandler(int messageTypeId) { I2CPMessageHandler handler = (I2CPMessageHandler) _handlers.get(new Integer(messageTypeId)); return handler; } diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index cc840560a..33c8adfe4 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -39,6 +39,7 @@ import net.i2p.data.i2cp.SessionId; import net.i2p.util.Clock; import net.i2p.util.I2PThread; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Implementation of an I2P session running over TCP. This class is NOT thread safe - @@ -47,7 +48,7 @@ import net.i2p.util.Log; * @author jrandom */ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener { - private final static Log _log = new Log(I2PSessionImpl.class); + private Log _log; /** who we are */ private Destination _myDestination; /** private key for decryption */ @@ -79,6 +80,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa protected I2CPMessageProducer _producer; /** map of integer --> MessagePayloadMessage */ Map _availableMessages; + + protected I2PClientMessageHandlerMap _handlerMap; + + /** used to seperate things out so we can get rid of singletons */ + protected I2PAppContext _context; /** MessageStatusMessage status from the most recent send that hasn't been consumed */ private List _receivedStatus; @@ -108,9 +114,12 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa * * @throws I2PSessionException if there is a problem loading the private keys or */ - public I2PSessionImpl(InputStream destKeyStream, Properties options) throws I2PSessionException { + public I2PSessionImpl(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException { + _context = context; + _log = context.logManager().getLog(I2PSessionImpl.class); + _handlerMap = new I2PClientMessageHandlerMap(context); _closed = true; - _producer = new I2CPMessageProducer(); + _producer = new I2CPMessageProducer(context); _availableMessages = new HashMap(); try { readDestination(destKeyStream); @@ -139,13 +148,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa _portNum = Integer.parseInt(portNum); } catch (NumberFormatException nfe) { if (_log.shouldLog(Log.WARN)) - _log.warn("Invalid port number specified, defaulting to " - + TestServer.LISTEN_PORT, nfe); + _log.warn("Invalid port number specified, defaulting to " + + TestServer.LISTEN_PORT, nfe); _portNum = TestServer.LISTEN_PORT; } } - private static Properties filter(Properties options) { + private Properties filter(Properties options) { Properties rv = new Properties(); for (Iterator iter = options.keySet().iterator(); iter.hasNext();) { String key = (String) iter.next(); @@ -212,7 +221,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa */ public void connect() throws I2PSessionException { _closed = false; - long startConnect = Clock.getInstance().now(); + long startConnect = _context.clock().now(); try { if (_log.shouldLog(Log.DEBUG)) _log.debug("connect begin to " + _hostname + ":" + _portNum); _socket = new Socket(_hostname, _portNum); @@ -251,7 +260,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa } } } - long connected = Clock.getInstance().now(); + long connected = _context.clock().now(); if (_log.shouldLog(Log.INFO)) _log.info("Lease set created with inbound tunnels after " + (connected - startConnect) @@ -339,7 +348,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa * */ public void messageReceived(I2CPMessageReader reader, I2CPMessage message) { - I2CPMessageHandler handler = I2PClientMessageHandlerMap.getHandler(message.getType()); + I2CPMessageHandler handler = _handlerMap.getHandler(message.getType()); if (handler == null) { if (_log.shouldLog(Log.WARN)) _log.warn("Unknown message or unhandleable message received: type = " diff --git a/core/java/src/net/i2p/client/I2PSessionImpl2.java b/core/java/src/net/i2p/client/I2PSessionImpl2.java index 966362008..03a19c927 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl2.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl2.java @@ -26,6 +26,7 @@ import net.i2p.data.i2cp.MessageStatusMessage; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Thread safe implementation of an I2P session running over TCP. @@ -33,7 +34,7 @@ import net.i2p.util.RandomSource; * @author jrandom */ class I2PSessionImpl2 extends I2PSessionImpl { - private final static Log _log = new Log(I2PSessionImpl2.class); + private Log _log; /** set of MessageState objects, representing all of the messages in the process of being sent */ private Set _sendingStates; @@ -48,8 +49,9 @@ class I2PSessionImpl2 extends I2PSessionImpl { * * @throws I2PSessionException if there is a problem loading the private keys or */ - public I2PSessionImpl2(InputStream destKeyStream, Properties options) throws I2PSessionException { - super(destKeyStream, options); + public I2PSessionImpl2(I2PAppContext ctx, InputStream destKeyStream, Properties options) throws I2PSessionException { + super(ctx, destKeyStream, options); + _log = ctx.logManager().getLog(I2PSessionImpl2.class); _sendingStates = new HashSet(32); } @@ -95,22 +97,22 @@ class I2PSessionImpl2 extends I2PSessionImpl { private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent) throws I2PSessionException { - SessionKey key = SessionKeyManager.getInstance().getCurrentKey(dest.getPublicKey()); - if (key == null) key = SessionKeyManager.getInstance().createSession(dest.getPublicKey()); - SessionTag tag = SessionKeyManager.getInstance().consumeNextAvailableTag(dest.getPublicKey(), key); + SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey()); + if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey()); + SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key); Set sentTags = null; - if (SessionKeyManager.getInstance().getAvailableTags(dest.getPublicKey(), key) < 10) { + if (_context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key) < 10) { sentTags = createNewTags(50); - } else if (SessionKeyManager.getInstance().getAvailableTimeLeft(dest.getPublicKey(), key) < 30 * 1000) { + } else if (_context.sessionKeyManager().getAvailableTimeLeft(dest.getPublicKey(), key) < 30 * 1000) { // if we have > 10 tags, but they expire in under 30 seconds, we want more sentTags = createNewTags(50); if (_log.shouldLog(Log.DEBUG)) _log.debug("Tags are almost expired, adding 50 new ones"); } SessionKey newKey = null; if (false) // rekey - newKey = KeyGenerator.getInstance().generateSessionKey(); + newKey = _context.keyGenerator().generateSessionKey(); - long nonce = (long) RandomSource.getInstance().nextInt(Integer.MAX_VALUE); + long nonce = (long)_context.random().nextInt(Integer.MAX_VALUE); MessageState state = new MessageState(nonce); state.setKey(key); state.setTags(sentTags); @@ -137,7 +139,8 @@ class I2PSessionImpl2 extends I2PSessionImpl { _log.debug("Adding sending state " + state.getMessageId() + " / " + state.getNonce()); _producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey); - state.waitFor(MessageStatusMessage.STATUS_SEND_ACCEPTED, Clock.getInstance().now() + getTimeout()); + state.waitFor(MessageStatusMessage.STATUS_SEND_ACCEPTED, + _context.clock().now() + getTimeout()); synchronized (_sendingStates) { _sendingStates.remove(state); } @@ -163,22 +166,22 @@ class I2PSessionImpl2 extends I2PSessionImpl { private boolean sendGuaranteed(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent) throws I2PSessionException { - SessionKey key = SessionKeyManager.getInstance().getCurrentKey(dest.getPublicKey()); - if (key == null) key = SessionKeyManager.getInstance().createSession(dest.getPublicKey()); - SessionTag tag = SessionKeyManager.getInstance().consumeNextAvailableTag(dest.getPublicKey(), key); + SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey()); + if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey()); + SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key); Set sentTags = null; - if (SessionKeyManager.getInstance().getAvailableTags(dest.getPublicKey(), key) < 10) { + if (_context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key) < 10) { sentTags = createNewTags(50); - } else if (SessionKeyManager.getInstance().getAvailableTimeLeft(dest.getPublicKey(), key) < 30 * 1000) { + } else if (_context.sessionKeyManager().getAvailableTimeLeft(dest.getPublicKey(), key) < 30 * 1000) { // if we have > 10 tags, but they expire in under 30 seconds, we want more sentTags = createNewTags(50); if (_log.shouldLog(Log.DEBUG)) _log.debug("Tags are almost expired, adding 50 new ones"); } SessionKey newKey = null; if (false) // rekey - newKey = KeyGenerator.getInstance().generateSessionKey(); + newKey = _context.keyGenerator().generateSessionKey(); - long nonce = (long) RandomSource.getInstance().nextInt(Integer.MAX_VALUE); + long nonce = (long)_context.random().nextInt(Integer.MAX_VALUE); MessageState state = new MessageState(nonce); state.setKey(key); state.setTags(sentTags); @@ -206,9 +209,11 @@ class I2PSessionImpl2 extends I2PSessionImpl { + state.getNonce()); _producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey); if (isGuaranteed()) - state.waitFor(MessageStatusMessage.STATUS_SEND_GUARANTEED_SUCCESS, Clock.getInstance().now() + SEND_TIMEOUT); + state.waitFor(MessageStatusMessage.STATUS_SEND_GUARANTEED_SUCCESS, + _context.clock().now() + SEND_TIMEOUT); else - state.waitFor(MessageStatusMessage.STATUS_SEND_ACCEPTED, Clock.getInstance().now() + SEND_TIMEOUT); + state.waitFor(MessageStatusMessage.STATUS_SEND_ACCEPTED, + _context.clock().now() + SEND_TIMEOUT); synchronized (_sendingStates) { _sendingStates.remove(state); } @@ -250,9 +255,9 @@ class I2PSessionImpl2 extends I2PSessionImpl { + state.getTags()); if ((state.getTags() != null) && (state.getTags().size() > 0)) { if (state.getNewKey() == null) - SessionKeyManager.getInstance().tagsDelivered(state.getTo().getPublicKey(), state.getKey(), state.getTags()); + _context.sessionKeyManager().tagsDelivered(state.getTo().getPublicKey(), state.getKey(), state.getTags()); else - SessionKeyManager.getInstance().tagsDelivered(state.getTo().getPublicKey(), state.getNewKey(), state.getTags()); + _context.sessionKeyManager().tagsDelivered(state.getTo().getPublicKey(), state.getNewKey(), state.getTags()); } } @@ -260,7 +265,7 @@ class I2PSessionImpl2 extends I2PSessionImpl { if (_log.shouldLog(Log.INFO)) _log.info("nack tags for msgId " + state.getMessageId() + " / " + state.getNonce() + " key = " + state.getKey()); - SessionKeyManager.getInstance().failTags(state.getTo().getPublicKey()); + _context.sessionKeyManager().failTags(state.getTo().getPublicKey()); } public void receiveStatus(int msgId, long nonce, int status) { diff --git a/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java b/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java index 7d546de94..ac8cef572 100644 --- a/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java +++ b/core/java/src/net/i2p/client/MessagePayloadMessageHandler.java @@ -16,6 +16,7 @@ import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.MessageId; import net.i2p.data.i2cp.MessagePayloadMessage; import net.i2p.data.i2cp.ReceiveMessageEndMessage; +import net.i2p.I2PAppContext; /** * Handle I2CP MessagePayloadMessages from the router delivering the contents @@ -25,8 +26,8 @@ import net.i2p.data.i2cp.ReceiveMessageEndMessage; * @author jrandom */ class MessagePayloadMessageHandler extends HandlerImpl { - public MessagePayloadMessageHandler() { - super(MessagePayloadMessage.MESSAGE_TYPE); + public MessagePayloadMessageHandler(I2PAppContext context) { + super(context, MessagePayloadMessage.MESSAGE_TYPE); } public void handleMessage(I2CPMessage message, I2PSessionImpl session) { @@ -53,7 +54,7 @@ class MessagePayloadMessageHandler extends HandlerImpl { */ private Payload decryptPayload(MessagePayloadMessage msg, I2PSessionImpl session) throws DataFormatException { Payload payload = msg.getPayload(); - byte[] data = ElGamalAESEngine.decrypt(payload.getEncryptedData(), session.getDecryptionKey()); + byte[] data = _context.elGamalAESEngine().decrypt(payload.getEncryptedData(), session.getDecryptionKey()); if (data == null) { _log .error("Error decrypting the payload to public key " diff --git a/core/java/src/net/i2p/client/MessageStatusMessageHandler.java b/core/java/src/net/i2p/client/MessageStatusMessageHandler.java index a5d1c00ad..3413aff3a 100644 --- a/core/java/src/net/i2p/client/MessageStatusMessageHandler.java +++ b/core/java/src/net/i2p/client/MessageStatusMessageHandler.java @@ -12,6 +12,7 @@ package net.i2p.client; import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.MessageStatusMessage; import net.i2p.data.i2cp.ReceiveMessageBeginMessage; +import net.i2p.I2PAppContext; /** * Handle I2CP MessageStatusMessages from the router. This currently only takes @@ -21,8 +22,8 @@ import net.i2p.data.i2cp.ReceiveMessageBeginMessage; * @author jrandom */ class MessageStatusMessageHandler extends HandlerImpl { - public MessageStatusMessageHandler() { - super(MessageStatusMessage.MESSAGE_TYPE); + public MessageStatusMessageHandler(I2PAppContext context) { + super(context, MessageStatusMessage.MESSAGE_TYPE); } public void handleMessage(I2CPMessage message, I2PSessionImpl session) { diff --git a/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java b/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java index 7cc0c8690..06bb3e808 100644 --- a/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java +++ b/core/java/src/net/i2p/client/RequestLeaseSetMessageHandler.java @@ -25,6 +25,7 @@ import net.i2p.data.SigningPublicKey; import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.RequestLeaseSetMessage; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Handle I2CP RequestLeaseSetMessage from the router by granting all leases @@ -35,8 +36,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl { private final static Log _log = new Log(RequestLeaseSetMessageHandler.class); private Map _existingLeaseSets; - public RequestLeaseSetMessageHandler() { - super(RequestLeaseSetMessage.MESSAGE_TYPE); + public RequestLeaseSetMessageHandler(I2PAppContext context) { + super(context, RequestLeaseSetMessage.MESSAGE_TYPE); _existingLeaseSets = new HashMap(32); } diff --git a/core/java/src/net/i2p/client/SessionStatusMessageHandler.java b/core/java/src/net/i2p/client/SessionStatusMessageHandler.java index 1ba816469..6f0ad741f 100644 --- a/core/java/src/net/i2p/client/SessionStatusMessageHandler.java +++ b/core/java/src/net/i2p/client/SessionStatusMessageHandler.java @@ -11,6 +11,7 @@ package net.i2p.client; import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.SessionStatusMessage; +import net.i2p.I2PAppContext; /** * Handle I2CP SessionStatusMessagese from the router, updating the session as @@ -19,8 +20,8 @@ import net.i2p.data.i2cp.SessionStatusMessage; * @author jrandom */ class SessionStatusMessageHandler extends HandlerImpl { - public SessionStatusMessageHandler() { - super(SessionStatusMessage.MESSAGE_TYPE); + public SessionStatusMessageHandler(I2PAppContext context) { + super(context, SessionStatusMessage.MESSAGE_TYPE); } public void handleMessage(I2CPMessage message, I2PSessionImpl session) { diff --git a/core/java/src/net/i2p/client/SetDateMessageHandler.java b/core/java/src/net/i2p/client/SetDateMessageHandler.java index 63ff1ae51..2cc52086e 100644 --- a/core/java/src/net/i2p/client/SetDateMessageHandler.java +++ b/core/java/src/net/i2p/client/SetDateMessageHandler.java @@ -12,6 +12,7 @@ package net.i2p.client; import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.SetDateMessage; import net.i2p.util.Clock; +import net.i2p.I2PAppContext; /** * Handle I2CP time messages from the router @@ -19,8 +20,8 @@ import net.i2p.util.Clock; * @author jrandom */ class SetDateMessageHandler extends HandlerImpl { - public SetDateMessageHandler() { - super(SetDateMessage.MESSAGE_TYPE); + public SetDateMessageHandler(I2PAppContext ctx) { + super(ctx, SetDateMessage.MESSAGE_TYPE); } public void handleMessage(I2CPMessage message, I2PSessionImpl session) { diff --git a/core/java/src/net/i2p/client/naming/DummyNamingService.java b/core/java/src/net/i2p/client/naming/DummyNamingService.java index 1bd18cd78..d826b0b06 100644 --- a/core/java/src/net/i2p/client/naming/DummyNamingService.java +++ b/core/java/src/net/i2p/client/naming/DummyNamingService.java @@ -8,11 +8,21 @@ package net.i2p.client.naming; import net.i2p.data.Destination; +import net.i2p.I2PAppContext; /** * A Dummy naming service that can only handle base64 destinations. */ class DummyNamingService extends NamingService { + /** + * The naming service should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + protected DummyNamingService(I2PAppContext context) { super(context); } + private DummyNamingService() { super(null); } + public Destination lookup(String hostname) { return lookupBase64(hostname); } diff --git a/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java b/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java index 636db1f0d..e997989c0 100644 --- a/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java +++ b/core/java/src/net/i2p/client/naming/HostsTxtNamingService.java @@ -14,12 +14,22 @@ import java.util.Properties; import net.i2p.data.Destination; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * A naming service based on the "hosts.txt" file. */ public class HostsTxtNamingService extends NamingService { + /** + * The naming service should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + protected HostsTxtNamingService(I2PAppContext context) { super(context); } + private HostsTxtNamingService() { super(null); } + /** * If this system property is specified, the tunnel will read the * given file for hostname=destKey values when resolving names @@ -35,7 +45,7 @@ public class HostsTxtNamingService extends NamingService { // Try to look it up in hosts.txt // Reload file each time to catch changes. // (and it's easier :P - String hostsfile = System.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE); + String hostsfile = _context.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE); Properties hosts = new Properties(); FileInputStream fis = null; try { diff --git a/core/java/src/net/i2p/client/naming/NamingService.java b/core/java/src/net/i2p/client/naming/NamingService.java index 904d1e709..b6b6d64a5 100644 --- a/core/java/src/net/i2p/client/naming/NamingService.java +++ b/core/java/src/net/i2p/client/naming/NamingService.java @@ -10,6 +10,9 @@ package net.i2p.client.naming; import net.i2p.data.DataFormatException; import net.i2p.data.Destination; import net.i2p.util.Log; +import net.i2p.I2PAppContext; + +import java.lang.reflect.Constructor; /** * Naming services create a subclass of this class. @@ -17,10 +20,23 @@ import net.i2p.util.Log; public abstract class NamingService { private final static Log _log = new Log(NamingService.class); + protected I2PAppContext _context; private static final String PROP_IMPL = "i2p.naming.impl"; private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService"; + + /** + * The naming service should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + protected NamingService(I2PAppContext context) { + _context = context; + } + private NamingService() {} + /** * Look up a host name. * @return the Destination for this host name, or @@ -52,23 +68,22 @@ public abstract class NamingService { } } - private static NamingService instance = null; - /** * Get a naming service instance. This method ensures that there * will be only one naming service instance (singleton) as well as * choose the implementation from the "i2p.naming.impl" system * property. */ - public static synchronized NamingService getInstance() { - if (instance == null) { - String impl = System.getProperty(PROP_IMPL, DEFAULT_IMPL); - try { - instance = (NamingService) Class.forName(impl).newInstance(); - } catch (Exception ex) { - _log.error("Cannot loadNaming service implementation", ex); - instance = new DummyNamingService(); // fallback - } + public static final synchronized NamingService createInstance(I2PAppContext context) { + NamingService instance = null; + String impl = context.getProperty(PROP_IMPL, DEFAULT_IMPL); + try { + Class cls = Class.forName(impl); + Constructor con = cls.getConstructor(new Class[] { I2PAppContext.class }); + instance = (NamingService)con.newInstance(new Object[] { context }); + } catch (Exception ex) { + _log.error("Cannot loadNaming service implementation", ex); + instance = new DummyNamingService(context); // fallback } return instance; } diff --git a/core/java/src/net/i2p/crypto/AESEngine.java b/core/java/src/net/i2p/crypto/AESEngine.java index a96870d15..1cdfcff16 100644 --- a/core/java/src/net/i2p/crypto/AESEngine.java +++ b/core/java/src/net/i2p/crypto/AESEngine.java @@ -19,26 +19,20 @@ import net.i2p.data.Hash; import net.i2p.data.SessionKey; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** - * Wrapper singleton for AES cypher operation. + * Dummy wrapper for AES cipher operation. * - * @author jrandom */ public class AESEngine { - private final static Log _log = new Log(AESEngine.class); - private static AESEngine _engine; - static { - if ("off".equals(System.getProperty("i2p.encryption", "on"))) - _engine = new AESEngine(); - else - _engine = new CryptixAESEngine(); + private Log _log; + private I2PAppContext _context; + public AESEngine(I2PAppContext ctx) { + _context = ctx; + _log = _context.logManager().getLog(AESEngine.class); } - - public static AESEngine getInstance() { - return _engine; - } - + /** Encrypt the payload with the session key * @param payload data to be encrypted * @param sessionKey private esession key to encrypt to @@ -59,13 +53,13 @@ public class AESEngine { if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null; ByteArrayOutputStream baos = new ByteArrayOutputStream(paddedSize + 64); - Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); + Hash h = _context.sha().calculateHash(sessionKey.getData()); try { h.writeBytes(baos); DataHelper.writeLong(baos, 4, payload.length); baos.write(payload); byte tv[] = baos.toByteArray(); - baos.write(ElGamalAESEngine.getPadding(tv.length, paddedSize)); + baos.write(ElGamalAESEngine.getPadding(_context, tv.length, paddedSize)); } catch (IOException ioe) { _log.error("Error writing data", ioe); return null; @@ -85,7 +79,7 @@ public class AESEngine { return null; } ByteArrayInputStream bais = new ByteArrayInputStream(decr); - Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); + Hash h = _context.sha().calculateHash(sessionKey.getData()); try { Hash rh = new Hash(); rh.readBytes(bais); @@ -127,20 +121,21 @@ public class AESEngine { } public static void main(String args[]) { - SessionKey key = KeyGenerator.getInstance().generateSessionKey(); + I2PAppContext ctx = new I2PAppContext(); + SessionKey key = ctx.keyGenerator().generateSessionKey(); byte iv[] = new byte[16]; RandomSource.getInstance().nextBytes(iv); byte sbuf[] = new byte[16]; RandomSource.getInstance().nextBytes(sbuf); - byte se[] = AESEngine.getInstance().encrypt(sbuf, key, iv); - byte sd[] = AESEngine.getInstance().decrypt(se, key, iv); - _log.debug("Short test: " + DataHelper.eq(sd, sbuf)); + byte se[] = ctx.AESEngine().encrypt(sbuf, key, iv); + byte sd[] = ctx.AESEngine().decrypt(se, key, iv); + ctx.logManager().getLog(AESEngine.class).debug("Short test: " + DataHelper.eq(sd, sbuf)); byte lbuf[] = new byte[1024]; RandomSource.getInstance().nextBytes(sbuf); - byte le[] = AESEngine.getInstance().safeEncrypt(lbuf, key, iv, 2048); - byte ld[] = AESEngine.getInstance().safeDecrypt(le, key, iv); - _log.debug("Long test: " + DataHelper.eq(ld, lbuf)); + byte le[] = ctx.AESEngine().safeEncrypt(lbuf, key, iv, 2048); + byte ld[] = ctx.AESEngine().safeDecrypt(le, key, iv); + ctx.logManager().getLog(AESEngine.class).debug("Long test: " + DataHelper.eq(ld, lbuf)); } } \ No newline at end of file diff --git a/core/java/src/net/i2p/crypto/AESInputStream.java b/core/java/src/net/i2p/crypto/AESInputStream.java index 008b4576d..ad2cb4c01 100644 --- a/core/java/src/net/i2p/crypto/AESInputStream.java +++ b/core/java/src/net/i2p/crypto/AESInputStream.java @@ -24,6 +24,7 @@ import net.i2p.data.SessionKey; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * This reads an underlying stream as written by AESOutputStream - AES256 encrypted @@ -36,8 +37,8 @@ import net.i2p.util.RandomSource; * */ public class AESInputStream extends FilterInputStream { - private final static Log _log = new Log(AESInputStream.class); - private final static CryptixAESEngine _engine = new CryptixAESEngine(); + private Log _log; + private I2PAppContext _context; private SessionKey _key; private byte[] _lastBlock; private boolean _eofFound; @@ -52,8 +53,10 @@ public class AESInputStream extends FilterInputStream { private final static int READ_SIZE = BLOCK_SIZE; private final static int DECRYPT_SIZE = BLOCK_SIZE - 1; - public AESInputStream(InputStream source, SessionKey key, byte iv[]) { + public AESInputStream(I2PAppContext context, InputStream source, SessionKey key, byte iv[]) { super(source); + _context = context; + _log = context.logManager().getLog(AESInputStream.class); _key = key; _lastBlock = new byte[BLOCK_SIZE]; System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE); @@ -223,8 +226,8 @@ public class AESInputStream extends FilterInputStream { byte block[] = new byte[BLOCK_SIZE]; for (int i = 0; i < numBlocks; i++) { System.arraycopy(encrypted, i * BLOCK_SIZE, block, 0, BLOCK_SIZE); - byte decrypted[] = _engine.decrypt(block, _key, _lastBlock); - byte data[] = CryptixAESEngine.xor(decrypted, _lastBlock); + byte decrypted[] = _context.AESEngine().decrypt(block, _key, _lastBlock); + byte data[] = DataHelper.xor(decrypted, _lastBlock); int cleaned[] = stripPadding(data); for (int j = 0; j < cleaned.length; j++) { if (((int) cleaned[j]) <= 0) { @@ -297,6 +300,8 @@ public class AESInputStream extends FilterInputStream { * Test AESOutputStream/AESInputStream */ public static void main(String args[]) { + I2PAppContext ctx = new I2PAppContext(); + Log log = ctx.logManager().getLog(AESInputStream.class); byte orig[] = new byte[1024 * 32]; RandomSource.getInstance().nextBytes(orig); //byte orig[] = "you are my sunshine, my only sunshine".getBytes(); @@ -304,40 +309,40 @@ public class AESInputStream extends FilterInputStream { byte iv[] = "there once was a".getBytes(); for (int i = 0; i < 20; i++) { - runTest(orig, key, iv); + runTest(ctx, orig, key, iv); } - _log.info("Done testing 32KB data"); + log.info("Done testing 32KB data"); orig = new byte[20]; RandomSource.getInstance().nextBytes(orig); for (int i = 0; i < 20; i++) { - runTest(orig, key, iv); + runTest(ctx, orig, key, iv); } - _log.info("Done testing 20 byte data"); + log.info("Done testing 20 byte data"); orig = new byte[3]; RandomSource.getInstance().nextBytes(orig); for (int i = 0; i < 20; i++) { - runTest(orig, key, iv); + runTest(ctx, orig, key, iv); } - _log.info("Done testing 3 byte data"); + log.info("Done testing 3 byte data"); orig = new byte[0]; RandomSource.getInstance().nextBytes(orig); for (int i = 0; i < 20; i++) { - runTest(orig, key, iv); + runTest(ctx, orig, key, iv); } - _log.info("Done testing 0 byte data"); + log.info("Done testing 0 byte data"); orig = new byte[32]; RandomSource.getInstance().nextBytes(orig); - runOffsetTest(orig, key, iv); + runOffsetTest(ctx, orig, key, iv); - _log.info("Done testing offset test (it should have come back with a statement NOT EQUAL!)"); + log.info("Done testing offset test (it should have come back with a statement NOT EQUAL!)"); try { Thread.sleep(30 * 1000); @@ -345,11 +350,12 @@ public class AESInputStream extends FilterInputStream { } } - private static void runTest(byte orig[], SessionKey key, byte[] iv) { + private static void runTest(I2PAppContext ctx, byte orig[], SessionKey key, byte[] iv) { + Log log = ctx.logManager().getLog(AESInputStream.class); try { long start = Clock.getInstance().now(); ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); - AESOutputStream out = new AESOutputStream(origStream, key, iv); + AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv); out.write(orig); out.close(); @@ -357,7 +363,7 @@ public class AESInputStream extends FilterInputStream { long endE = Clock.getInstance().now(); ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encrypted); - AESInputStream in = new AESInputStream(encryptedStream, key, iv); + AESInputStream in = new AESInputStream(ctx, encryptedStream, key, iv); ByteArrayOutputStream baos = new ByteArrayOutputStream(512); byte buf[] = new byte[1024 * 32]; int read = DataHelper.read(in, buf); @@ -370,65 +376,66 @@ public class AESInputStream extends FilterInputStream { Hash newHash = SHA256Generator.getInstance().calculateHash(fin); boolean eq = origHash.equals(newHash); if (eq) - _log.info("Equal hashes. hash: " + origHash); + log.info("Equal hashes. hash: " + origHash); else - _log.error("NOT EQUAL! \norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin)); + log.error("NOT EQUAL! \norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin)); boolean ok = DataHelper.eq(orig, fin); - _log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); - _log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms"); - _log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); - _log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); + log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); + log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms"); + log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); + log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); } catch (Throwable t) { - _log.error("ERROR transferring", t); + log.error("ERROR transferring", t); } //try { Thread.sleep(5000); } catch (Throwable t) {} } - private static void runOffsetTest(byte orig[], SessionKey key, byte[] iv) { + private static void runOffsetTest(I2PAppContext ctx, byte orig[], SessionKey key, byte[] iv) { + Log log = ctx.logManager().getLog(AESInputStream.class); try { long start = Clock.getInstance().now(); ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); - AESOutputStream out = new AESOutputStream(origStream, key, iv); + AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv); out.write(orig); out.close(); byte encrypted[] = origStream.toByteArray(); long endE = Clock.getInstance().now(); - _log.info("Encrypted segment length: " + encrypted.length); + log.info("Encrypted segment length: " + encrypted.length); byte encryptedSegment[] = new byte[40]; System.arraycopy(encrypted, 0, encryptedSegment, 0, 40); ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encryptedSegment); - AESInputStream in = new AESInputStream(encryptedStream, key, iv); + AESInputStream in = new AESInputStream(ctx, encryptedStream, key, iv); ByteArrayOutputStream baos = new ByteArrayOutputStream(512); byte buf[] = new byte[1024 * 32]; int read = DataHelper.read(in, buf); int remaining = in.remainingBytes(); int readyBytes = in.readyBytes(); - _log.info("Read: " + read); + log.info("Read: " + read); if (read > 0) baos.write(buf, 0, read); in.close(); byte fin[] = baos.toByteArray(); - _log.info("fin.length: " + fin.length + " remaining: " + remaining + " ready: " + readyBytes); + log.info("fin.length: " + fin.length + " remaining: " + remaining + " ready: " + readyBytes); long end = Clock.getInstance().now(); Hash origHash = SHA256Generator.getInstance().calculateHash(orig); Hash newHash = SHA256Generator.getInstance().calculateHash(fin); boolean eq = origHash.equals(newHash); if (eq) - _log.info("Equal hashes. hash: " + origHash); + log.info("Equal hashes. hash: " + origHash); else - _log.error("NOT EQUAL! \norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin)); + log.error("NOT EQUAL! \norig: \t" + Base64.encode(orig) + "\nnew : \t" + Base64.encode(fin)); boolean ok = DataHelper.eq(orig, fin); - _log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); - _log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms"); - _log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); - _log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); + log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); + log.debug("Time to D(E(" + orig.length + ")): " + (end - start) + "ms"); + log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); + log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); } catch (Throwable t) { - _log.error("ERROR transferring", t); + log.error("ERROR transferring", t); } //try { Thread.sleep(5000); } catch (Throwable t) {} } diff --git a/core/java/src/net/i2p/crypto/AESOutputStream.java b/core/java/src/net/i2p/crypto/AESOutputStream.java index c8d3c9d92..c1413c7e2 100644 --- a/core/java/src/net/i2p/crypto/AESOutputStream.java +++ b/core/java/src/net/i2p/crypto/AESOutputStream.java @@ -16,7 +16,9 @@ import java.io.OutputStream; import java.util.Arrays; import net.i2p.data.SessionKey; +import net.i2p.data.DataHelper; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * This writes everything as CBC with PKCS#5 padding, but each block is padded @@ -28,8 +30,8 @@ import net.i2p.util.Log; * */ public class AESOutputStream extends FilterOutputStream { - private final static CryptixAESEngine _engine = new CryptixAESEngine(); - private final static Log _log = new Log(AESOutputStream.class); + private Log _log; + private I2PAppContext _context; private SessionKey _key; private byte[] _lastBlock; private ByteArrayOutputStream _inBuf; @@ -42,8 +44,10 @@ public class AESOutputStream extends FilterOutputStream { private final static int BLOCK_SIZE = CryptixRijndael_Algorithm._BLOCK_SIZE; private final static int MAX_BUF = 256; - public AESOutputStream(OutputStream source, SessionKey key, byte[] iv) { + public AESOutputStream(I2PAppContext context, OutputStream source, SessionKey key, byte[] iv) { super(source); + _context = context; + _log = context.logManager().getLog(AESOutputStream.class); _key = key; _lastBlock = new byte[BLOCK_SIZE]; System.arraycopy(iv, 0, _lastBlock, 0, BLOCK_SIZE); @@ -104,8 +108,8 @@ public class AESOutputStream extends FilterOutputStream { block[BLOCK_SIZE - 1] = 0x01; // the padding byte for "full" blocks for (int i = 0; i < numBlocks; i++) { System.arraycopy(src, i * 15, block, 0, 15); - byte data[] = _engine.xor(block, _lastBlock); - byte encrypted[] = _engine.encrypt(data, _key, _lastBlock); + byte data[] = DataHelper.xor(block, _lastBlock); + byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock); _cumulativeWritten += encrypted.length; out.write(encrypted); System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); @@ -118,8 +122,8 @@ public class AESOutputStream extends FilterOutputStream { int paddingBytes = BLOCK_SIZE - remainingBytes; System.arraycopy(src, numBlocks * 15, block, 0, remainingBytes); Arrays.fill(block, remainingBytes, BLOCK_SIZE, (byte) paddingBytes); - byte data[] = _engine.xor(block, _lastBlock); - byte encrypted[] = _engine.encrypt(data, _key, _lastBlock); + byte data[] = DataHelper.xor(block, _lastBlock); + byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock); out.write(encrypted); System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); _cumulativePadding += paddingBytes; diff --git a/core/java/src/net/i2p/crypto/CryptixAESEngine.java b/core/java/src/net/i2p/crypto/CryptixAESEngine.java index cd0337ed5..397f67c32 100644 --- a/core/java/src/net/i2p/crypto/CryptixAESEngine.java +++ b/core/java/src/net/i2p/crypto/CryptixAESEngine.java @@ -13,6 +13,7 @@ import java.security.InvalidKeyException; import net.i2p.data.SessionKey; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Wrapper for AES cypher operation using Cryptix's Rijndael implementation. Implements @@ -23,10 +24,15 @@ import net.i2p.util.Log; * @author jrandom, thecrypto */ public class CryptixAESEngine extends AESEngine { - private final static Log _log = new Log(CryptixAESEngine.class); + private Log _log; private final static CryptixRijndael_Algorithm _algo = new CryptixRijndael_Algorithm(); private final static boolean USE_FAKE_CRYPTO = false; private final static byte FAKE_KEY = 0x2A; + + public CryptixAESEngine(I2PAppContext context) { + super(context); + _log = context.logManager().getLog(CryptixAESEngine.class); + } public byte[] encrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) { if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null) @@ -116,7 +122,7 @@ public class CryptixAESEngine extends AESEngine { * @param sessionKey private esession key to encrypt to * @return encrypted data */ - final static byte[] encrypt(byte payload[], SessionKey sessionKey) { + final byte[] encrypt(byte payload[], SessionKey sessionKey) { try { Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16); byte rv[] = new byte[payload.length]; @@ -133,7 +139,7 @@ public class CryptixAESEngine extends AESEngine { * @param sessionKey private session key * @return unencrypted data */ - final static byte[] decrypt(byte payload[], SessionKey sessionKey) { + final byte[] decrypt(byte payload[], SessionKey sessionKey) { try { Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16); byte rv[] = new byte[payload.length]; diff --git a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java index 52d95285a..4187348aa 100644 --- a/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java +++ b/core/java/src/net/i2p/crypto/DHSessionKeyBuilder.java @@ -20,6 +20,7 @@ import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.NativeBigInteger; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Generate a new session key through a diffie hellman exchange. This uses the @@ -62,22 +63,23 @@ public class DHSessionKeyBuilder { public final static String DEFAULT_DH_PRECALC_DELAY = "1000"; static { + I2PAppContext ctx = I2PAppContext.getGlobalContext(); try { - int val = Integer.parseInt(System.getProperty(PROP_DH_PRECALC_MIN, DEFAULT_DH_PRECALC_MIN)); + 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(System.getProperty(PROP_DH_PRECALC_MAX, DEFAULT_DH_PRECALC_MAX)); + 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(System.getProperty(PROP_DH_PRECALC_DELAY, DEFAULT_DH_PRECALC_DELAY)); + 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); @@ -266,6 +268,7 @@ public class DHSessionKeyBuilder { Thread.sleep(20 * 1000); } catch (InterruptedException ie) { } + I2PAppContext ctx = new I2PAppContext(); _log.debug("\n\n\n\nBegin test\n"); long negTime = 0; for (int i = 0; i < 5; i++) { @@ -289,8 +292,8 @@ public class DHSessionKeyBuilder { byte iv[] = new byte[16]; RandomSource.getInstance().nextBytes(iv); String origVal = "1234567890123456"; // 16 bytes max using AESEngine - byte enc[] = AESEngine.getInstance().encrypt(origVal.getBytes(), key1, iv); - byte dec[] = AESEngine.getInstance().decrypt(enc, key2, iv); + byte enc[] = ctx.AESEngine().encrypt(origVal.getBytes(), key1, iv); + byte dec[] = ctx.AESEngine().decrypt(enc, key2, iv); String tranVal = new String(dec); if (origVal.equals(tranVal)) _log.debug("**Success: D(E(val)) == val"); diff --git a/core/java/src/net/i2p/crypto/DSAEngine.java b/core/java/src/net/i2p/crypto/DSAEngine.java index c19a28cc7..331edefb4 100644 --- a/core/java/src/net/i2p/crypto/DSAEngine.java +++ b/core/java/src/net/i2p/crypto/DSAEngine.java @@ -39,17 +39,22 @@ import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.NativeBigInteger; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; public class DSAEngine { - private final static Log _log = new Log(DSAEngine.class); - private static DSAEngine _instance = new DSAEngine(); + private Log _log; + private I2PAppContext _context; - public static DSAEngine getInstance() { - return _instance; + public DSAEngine(I2PAppContext context) { + _log = context.logManager().getLog(DSAEngine.class); + _context = context; } - + public static DSAEngine getInstance() { + return I2PAppContext.getGlobalContext().dsa(); + } + public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) { - long start = Clock.getInstance().now(); + long start = _context.clock().now(); byte[] sigbytes = signature.getData(); byte rbytes[] = new byte[20]; @@ -65,22 +70,20 @@ public class DSAEngine { BigInteger r = new NativeBigInteger(1, rbytes); BigInteger y = new NativeBigInteger(1, verifyingKey.getData()); BigInteger w = s.modInverse(CryptoConstants.dsaq); - BigInteger u1 = ((new NativeBigInteger(1, calculateHash(signedData).getData())).multiply(w)) - .mod(CryptoConstants.dsaq); + byte data[] = calculateHash(signedData).getData(); + NativeBigInteger bi = new NativeBigInteger(1, data); + BigInteger u1 = bi.multiply(w).mod(CryptoConstants.dsaq); BigInteger u2 = r.multiply(w).mod(CryptoConstants.dsaq); - BigInteger v = ((CryptoConstants.dsag.modPow(u1, CryptoConstants.dsap)) - .multiply(y.modPow(u2, - CryptoConstants.dsap))) - .mod( - CryptoConstants.dsap) - .mod( - CryptoConstants.dsaq); + BigInteger modval = CryptoConstants.dsag.modPow(u1, CryptoConstants.dsap); + BigInteger modmulval = modval.multiply(y.modPow(u2,CryptoConstants.dsap)); + BigInteger v = (modmulval).mod(CryptoConstants.dsap).mod(CryptoConstants.dsaq); boolean ok = v.compareTo(r) == 0; - long diff = Clock.getInstance().now() - start; + long diff = _context.clock().now() - start; if (diff > 1000) { - if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to verify the signature (" + diff + "ms)"); + if (_log.shouldLog(Log.WARN)) + _log.warn("Took too long to verify the signature (" + diff + "ms)"); } return ok; @@ -88,13 +91,13 @@ public class DSAEngine { public Signature sign(byte data[], SigningPrivateKey signingKey) { if ((signingKey == null) || (data == null) || (data.length <= 0)) return null; - long start = Clock.getInstance().now(); + long start = _context.clock().now(); Signature sig = new Signature(); BigInteger k; do { - k = new BigInteger(160, RandomSource.getInstance()); + k = new BigInteger(160, _context.random()); } while (k.compareTo(CryptoConstants.dsaq) != 1); BigInteger r = CryptoConstants.dsag.modPow(k, CryptoConstants.dsap).mod(CryptoConstants.dsaq); @@ -139,7 +142,7 @@ public class DSAEngine { } sig.setData(out); - long diff = Clock.getInstance().now() - start; + long diff = _context.clock().now() - start; if (diff > 1000) { if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to sign (" + diff + "ms)"); } diff --git a/core/java/src/net/i2p/crypto/DummyElGamalEngine.java b/core/java/src/net/i2p/crypto/DummyElGamalEngine.java index d86428ded..8a6376a50 100644 --- a/core/java/src/net/i2p/crypto/DummyElGamalEngine.java +++ b/core/java/src/net/i2p/crypto/DummyElGamalEngine.java @@ -17,6 +17,7 @@ import net.i2p.data.Hash; import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Fake ElG E and D, useful for when performance isn't being tested @@ -26,11 +27,19 @@ import net.i2p.util.Log; public class DummyElGamalEngine extends ElGamalEngine { private final static Log _log = new Log(DummyElGamalEngine.class); - public DummyElGamalEngine() { + /** + * The ElGamal engine should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + public DummyElGamalEngine(I2PAppContext context) { + super(context); _log.log(Log.CRIT, "Dummy ElGamal engine in use! NO DATA SECURITY. Danger Will Robinson, Danger!", new Exception("I really hope you know what you're doing")); } - + private DummyElGamalEngine() { super(null); } + /** encrypt the data to the public key * @return encrypted data * @param publicKey public key encrypt to diff --git a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java index 1e9e54fa0..08d455cc5 100644 --- a/core/java/src/net/i2p/crypto/ElGamalAESEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalAESEngine.java @@ -29,6 +29,7 @@ import net.i2p.stat.StatManager; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Handles the actual ElGamal+AES encryption and decryption scenarios using the @@ -37,28 +38,27 @@ import net.i2p.util.RandomSource; public class ElGamalAESEngine { private final static Log _log = new Log(ElGamalAESEngine.class); private final static int MIN_ENCRYPTED_SIZE = 80; // smallest possible resulting size + private I2PAppContext _context; - static { - StatManager.getInstance() - .createFrequencyStat("crypto.elGamalAES.encryptNewSession", - "how frequently we encrypt to a new ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); - StatManager.getInstance() - .createFrequencyStat("crypto.elGamalAES.encryptExistingSession", - "how frequently we encrypt to an existing ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); - StatManager.getInstance() - .createFrequencyStat("crypto.elGamalAES.decryptNewSession", - "how frequently we decrypt with a new ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); - StatManager.getInstance() - .createFrequencyStat("crypto.elGamalAES.decryptExistingSession", - "how frequently we decrypt with an existing ElGamal/AES+SessionTag session?", - "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); - StatManager.getInstance() - .createFrequencyStat("crypto.elGamalAES.decryptFail", - "how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption", - new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + private ElGamalAESEngine() {} + public ElGamalAESEngine(I2PAppContext ctx) { + _context = ctx; + + _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptNewSession", + "how frequently we encrypt to a new ElGamal/AES+SessionTag session?", + "Encryption", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l}); + _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptExistingSession", + "how frequently we encrypt to an existing ElGamal/AES+SessionTag session?", + "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptNewSession", + "how frequently we decrypt with a new ElGamal/AES+SessionTag session?", + "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptExistingSession", + "how frequently we decrypt with an existing ElGamal/AES+SessionTag session?", + "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); + _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptFail", + "how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption", + new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); } /** @@ -66,7 +66,7 @@ public class ElGamalAESEngine { * ElGamal+AES algorithm in the data structure spec. * */ - public static byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException { + public byte[] decrypt(byte data[], PrivateKey targetPrivateKey) throws DataFormatException { if (data == null) { if (_log.shouldLog(Log.WARN)) _log.warn("Null data being decrypted?"); return null; @@ -79,7 +79,7 @@ public class ElGamalAESEngine { byte tag[] = new byte[32]; System.arraycopy(data, 0, tag, 0, tag.length); SessionTag st = new SessionTag(tag); - SessionKey key = SessionKeyManager.getInstance().consumeTag(st); + SessionKey key = _context.sessionKeyManager().consumeTag(st); SessionKey foundKey = new SessionKey(); foundKey.setData(null); SessionKey usedKey = new SessionKey(); @@ -90,16 +90,16 @@ public class ElGamalAESEngine { usedKey.setData(key.getData()); decrypted = decryptExistingSession(data, key, targetPrivateKey, foundTags, usedKey, foundKey); if (decrypted != null) - StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptExistingSession"); + _context.statManager().updateFrequency("crypto.elGamalAES.decryptExistingSession"); else - StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptFailed"); + _context.statManager().updateFrequency("crypto.elGamalAES.decryptFailed"); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Key is NOT known for tag " + st); decrypted = decryptNewSession(data, targetPrivateKey, foundTags, usedKey, foundKey); if (decrypted != null) - StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptNewSession"); + _context.statManager().updateFrequency("crypto.elGamalAES.decryptNewSession"); else - StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptFailed"); + _context.statManager().updateFrequency("crypto.elGamalAES.decryptFailed"); } if ((key == null) && (decrypted == null)) { @@ -109,10 +109,10 @@ public class ElGamalAESEngine { if (foundTags.size() > 0) { if (foundKey.getData() != null) { if (_log.shouldLog(Log.DEBUG)) _log.debug("Found key: " + foundKey); - SessionKeyManager.getInstance().tagsReceived(foundKey, foundTags); + _context.sessionKeyManager().tagsReceived(foundKey, foundTags); } else { if (_log.shouldLog(Log.DEBUG)) _log.debug("Used key: " + usedKey); - SessionKeyManager.getInstance().tagsReceived(usedKey, foundTags); + _context.sessionKeyManager().tagsReceived(usedKey, foundTags); } } return decrypted; @@ -132,7 +132,7 @@ public class ElGamalAESEngine { * * @return null if decryption fails */ - static byte[] decryptNewSession(byte data[], PrivateKey targetPrivateKey, Set foundTags, SessionKey usedKey, + byte[] decryptNewSession(byte data[], PrivateKey targetPrivateKey, Set foundTags, SessionKey usedKey, SessionKey foundKey) throws DataFormatException { if (data == null) { if (_log.shouldLog(Log.WARN)) _log.warn("Data is null, unable to decrypt new session"); @@ -147,7 +147,7 @@ public class ElGamalAESEngine { } else { System.arraycopy(data, 0, elgEncr, 514 - data.length, data.length); } - byte elgDecr[] = ElGamalEngine.getInstance().decrypt(elgEncr, targetPrivateKey); + byte elgDecr[] = _context.elGamalEngine().decrypt(elgEncr, targetPrivateKey); if (elgDecr == null) return null; ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr); @@ -170,7 +170,7 @@ public class ElGamalAESEngine { //_log.debug("Pre IV for decryptNewSession: " + DataHelper.toString(preIV, 32)); //_log.debug("SessionKey for decryptNewSession: " + DataHelper.toString(key.getData(), 32)); - Hash ivHash = SHA256Generator.getInstance().calculateHash(preIV); + Hash ivHash = _context.sha().calculateHash(preIV); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); @@ -200,13 +200,13 @@ public class ElGamalAESEngine { * @param foundKey session key which may be filled with a new sessionKey found during decryption * */ - static byte[] decryptExistingSession(byte data[], SessionKey key, PrivateKey targetPrivateKey, Set foundTags, + byte[] decryptExistingSession(byte data[], SessionKey key, PrivateKey targetPrivateKey, Set foundTags, SessionKey usedKey, SessionKey foundKey) throws DataFormatException { byte preIV[] = new byte[32]; System.arraycopy(data, 0, preIV, 0, preIV.length); byte encr[] = new byte[data.length - 32]; System.arraycopy(data, 32, encr, 0, encr.length); - Hash ivHash = SHA256Generator.getInstance().calculateHash(preIV); + Hash ivHash = _context.sha().calculateHash(preIV); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); @@ -246,12 +246,12 @@ public class ElGamalAESEngine { * @param foundTags set which is filled with any sessionTags found during decryption * @param foundKey session key which may be filled with a new sessionKey found during decryption */ - static byte[] decryptAESBlock(byte encrypted[], SessionKey key, byte iv[], byte sentTag[], Set foundTags, + byte[] decryptAESBlock(byte encrypted[], SessionKey key, byte iv[], byte sentTag[], Set foundTags, SessionKey foundKey) throws DataFormatException { //_log.debug("iv for decryption: " + DataHelper.toString(iv, 16)); //_log.debug("decrypting AES block. encr.length = " + (encrypted == null? -1 : encrypted.length) + " sentTag: " + DataHelper.toString(sentTag, 32)); - byte decrypted[] = AESEngine.getInstance().decrypt(encrypted, key, iv); - Hash h = SHA256Generator.getInstance().calculateHash(decrypted); + byte decrypted[] = _context.AESEngine().decrypt(encrypted, key, iv); + Hash h = _context.sha().calculateHash(decrypted); //_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); try { SessionKey newKey = null; @@ -289,7 +289,7 @@ public class ElGamalAESEngine { byte unencrData[] = new byte[(int) len]; read = bais.read(unencrData); if (read != unencrData.length) throw new Exception("Invalid size of the data read"); - Hash calcHash = SHA256Generator.getInstance().calculateHash(unencrData); + Hash calcHash = _context.sha().calculateHash(unencrData); if (calcHash.equals(readHash)) { // everything matches. w00t. foundTags.addAll(tags); @@ -317,17 +317,17 @@ public class ElGamalAESEngine { * @param paddedSize minimum size in bytes of the body after padding it (if less than the * body's real size, no bytes are appended but the body is not truncated) */ - public static byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, + public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, SessionTag currentTag, SessionKey newKey, long paddedSize) { if (currentTag == null) { if (_log.shouldLog(Log.INFO)) _log.info("Current tag is null, encrypting as new session", new Exception("encrypt new")); - StatManager.getInstance().updateFrequency("crypto.elGamalAES.encryptNewSession"); + _context.statManager().updateFrequency("crypto.elGamalAES.encryptNewSession"); return encryptNewSession(data, target, key, tagsForDelivery, newKey, paddedSize); } else { if (_log.shouldLog(Log.INFO)) _log.info("Current tag is NOT null, encrypting as existing session", new Exception("encrypt existing")); - StatManager.getInstance().updateFrequency("crypto.elGamalAES.encryptExistingSession"); + _context.statManager().updateFrequency("crypto.elGamalAES.encryptExistingSession"); return encryptExistingSession(data, target, key, tagsForDelivery, currentTag, newKey, paddedSize); } } @@ -335,7 +335,7 @@ public class ElGamalAESEngine { /** * Encrypt the data to the target using the given key and deliver the specified tags */ - public static byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, + public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, SessionTag currentTag, long paddedSize) { return encrypt(data, target, key, tagsForDelivery, currentTag, null, paddedSize); } @@ -343,14 +343,14 @@ public class ElGamalAESEngine { /** * Encrypt the data to the target using the given key and deliver the specified tags */ - public static byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, long paddedSize) { + public byte[] encrypt(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, long paddedSize) { return encrypt(data, target, key, tagsForDelivery, null, null, paddedSize); } /** * Encrypt the data to the target using the given key delivering no tags */ - public static byte[] encrypt(byte data[], PublicKey target, SessionKey key, long paddedSize) { + public byte[] encrypt(byte data[], PublicKey target, SessionKey key, long paddedSize) { return encrypt(data, target, key, null, null, null, paddedSize); } @@ -370,25 +370,25 @@ public class ElGamalAESEngine { * - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0 * */ - static byte[] encryptNewSession(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, + byte[] encryptNewSession(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, SessionKey newKey, long paddedSize) { //_log.debug("Encrypting to a NEW session"); try { ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(64); key.writeBytes(elgSrc); byte preIV[] = new byte[32]; - RandomSource.getInstance().nextBytes(preIV); + _context.random().nextBytes(preIV); elgSrc.write(preIV); byte rnd[] = new byte[158]; - RandomSource.getInstance().nextBytes(rnd); + _context.random().nextBytes(rnd); elgSrc.write(rnd); elgSrc.flush(); //_log.debug("Pre IV for encryptNewSession: " + DataHelper.toString(preIV, 32)); //_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32)); - long before = Clock.getInstance().now(); - byte elgEncr[] = ElGamalEngine.getInstance().encrypt(elgSrc.toByteArray(), target); - long after = Clock.getInstance().now(); + long before = _context.clock().now(); + byte elgEncr[] = _context.elGamalEngine().encrypt(elgSrc.toByteArray(), target); + long after = _context.clock().now(); if (_log.shouldLog(Log.INFO)) _log.info("elgEngine.encrypt of the session key took " + (after - before) + "ms"); if (elgEncr.length < 514) { @@ -400,7 +400,7 @@ public class ElGamalAESEngine { } //_log.debug("ElGamal encrypted length: " + elgEncr.length + " elGamal source length: " + elgSrc.toByteArray().length); - Hash ivHash = SHA256Generator.getInstance().calculateHash(preIV); + Hash ivHash = _context.sha().calculateHash(preIV); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); byte aesEncr[] = encryptAESBlock(data, key, iv, tagsForDelivery, newKey, paddedSize); @@ -410,7 +410,7 @@ public class ElGamalAESEngine { System.arraycopy(elgEncr, 0, rv, 0, elgEncr.length); System.arraycopy(aesEncr, 0, rv, elgEncr.length, aesEncr.length); //_log.debug("Return length: " + rv.length); - long finish = Clock.getInstance().now(); + long finish = _context.clock().now(); if (_log.shouldLog(Log.DEBUG)) _log.debug("after the elgEngine.encrypt took a total of " + (finish - after) + "ms"); return rv; @@ -436,14 +436,14 @@ public class ElGamalAESEngine { * - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0 * */ - static byte[] encryptExistingSession(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, + byte[] encryptExistingSession(byte data[], PublicKey target, SessionKey key, Set tagsForDelivery, SessionTag currentTag, SessionKey newKey, long paddedSize) { //_log.debug("Encrypting to an EXISTING session"); byte rawTag[] = currentTag.getData(); //_log.debug("Pre IV for encryptExistingSession (aka tag): " + currentTag.toString()); //_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32)); - Hash ivHash = SHA256Generator.getInstance().calculateHash(rawTag); + Hash ivHash = _context.sha().calculateHash(rawTag); byte iv[] = new byte[16]; System.arraycopy(ivHash.getData(), 0, iv, 0, 16); @@ -469,7 +469,7 @@ public class ElGamalAESEngine { * - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0 * */ - final static byte[] encryptAESBlock(byte data[], SessionKey key, byte[] iv, Set tagsForDelivery, SessionKey newKey, + final byte[] encryptAESBlock(byte data[], SessionKey key, byte[] iv, Set tagsForDelivery, SessionKey newKey, long paddedSize) { //_log.debug("iv for encryption: " + DataHelper.toString(iv, 16)); //_log.debug("Encrypting AES"); @@ -484,7 +484,7 @@ public class ElGamalAESEngine { //_log.debug("# tags created, registered, and written: " + tags.size()); DataHelper.writeLong(aesSrc, 4, data.length); //_log.debug("data length: " + data.length); - Hash hash = SHA256Generator.getInstance().calculateHash(data); + Hash hash = _context.sha().calculateHash(data); hash.writeBytes(aesSrc); //_log.debug("hash of data: " + DataHelper.toString(hash.getData(), 32)); if (newKey == null) { @@ -499,14 +499,14 @@ public class ElGamalAESEngine { aesSrc.write(data); int len = aesSrc.toByteArray().length; //_log.debug("raw data written: " + len); - byte padding[] = getPadding(len, paddedSize); + byte padding[] = getPadding(_context, len, paddedSize); //_log.debug("padding length: " + padding.length); aesSrc.write(padding); byte aesUnencr[] = aesSrc.toByteArray(); - Hash h = SHA256Generator.getInstance().calculateHash(aesUnencr); + Hash h = _context.sha().calculateHash(aesUnencr); //_log.debug("Hash of entire aes block before encryption: (len=" + aesUnencr.length + ")\n" + DataHelper.toString(h.getData(), 32)); - byte aesEncr[] = AESEngine.getInstance().encrypt(aesUnencr, key, iv); + byte aesEncr[] = _context.AESEngine().encrypt(aesUnencr, key, iv); //_log.debug("Encrypted length: " + aesEncr.length); return aesEncr; } catch (IOException ioe) { @@ -523,7 +523,7 @@ public class ElGamalAESEngine { * at least minPaddedSize * */ - final static byte[] getPadding(int curSize, long minPaddedSize) { + final static byte[] getPadding(I2PAppContext context, int curSize, long minPaddedSize) { int diff = 0; if (curSize < minPaddedSize) { diff = (int) minPaddedSize - curSize; @@ -532,7 +532,7 @@ public class ElGamalAESEngine { int numPadding = diff; if (((curSize + diff) % 16) != 0) numPadding += (16 - ((curSize + diff) % 16)); byte rv[] = new byte[numPadding]; - RandomSource.getInstance().nextBytes(rv); + context.random().nextBytes(rv); return rv; } diff --git a/core/java/src/net/i2p/crypto/ElGamalEngine.java b/core/java/src/net/i2p/crypto/ElGamalEngine.java index 03923fa80..f90f9fedc 100644 --- a/core/java/src/net/i2p/crypto/ElGamalEngine.java +++ b/core/java/src/net/i2p/crypto/ElGamalEngine.java @@ -43,6 +43,7 @@ import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.NativeBigInteger; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Wrapper for ElGamal encryption/signature schemes. @@ -56,25 +57,28 @@ import net.i2p.util.RandomSource; */ public class ElGamalEngine { - private final static Log _log = new Log(ElGamalEngine.class); - private static ElGamalEngine _engine; - static { - if ("off".equals(System.getProperty("i2p.encryption", "on"))) - _engine = new DummyElGamalEngine(); - else - _engine = new ElGamalEngine(); - - StatManager.getInstance().createRateStat("crypto.elGamal.encrypt", - "how long does it take to do a full ElGamal encryption", "Encryption", - new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); - StatManager.getInstance().createRateStat("crypto.elGamal.decrypt", - "how long does it take to do a full ElGamal decryption", "Encryption", - new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); + private Log _log; + private I2PAppContext _context; + + /** + * The ElGamal engine should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + public ElGamalEngine(I2PAppContext context) { + context.statManager().createRateStat("crypto.elGamal.encrypt", + "how long does it take to do a full ElGamal encryption", "Encryption", + new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); + context.statManager().createRateStat("crypto.elGamal.decrypt", + "how long does it take to do a full ElGamal decryption", "Encryption", + new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); + _context = context; + _log = context.logManager().getLog(ElGamalEngine.class); } + private ElGamalEngine() {} - public static ElGamalEngine getInstance() { - return _engine; - } + private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02}); private BigInteger[] getNextYK() { @@ -91,12 +95,12 @@ public class ElGamalEngine { throw new IllegalArgumentException("Data to encrypt must be < 223 bytes at the moment"); if (publicKey == null) throw new IllegalArgumentException("Null public key specified"); - long start = Clock.getInstance().now(); + long start = _context.clock().now(); ByteArrayOutputStream baos = new ByteArrayOutputStream(256); try { baos.write(0xFF); - Hash hash = SHA256Generator.getInstance().calculateHash(data); + Hash hash = _context.sha().calculateHash(data); hash.writeBytes(baos); baos.write(data); baos.flush(); @@ -106,25 +110,25 @@ public class ElGamalEngine { } byte d2[] = baos.toByteArray(); - long t0 = Clock.getInstance().now(); + long t0 = _context.clock().now(); BigInteger m = new NativeBigInteger(1, d2); - long t1 = Clock.getInstance().now(); + long t1 = _context.clock().now(); if (m.compareTo(CryptoConstants.elgp) >= 0) throw new IllegalArgumentException("ARGH. Data cannot be larger than the ElGamal prime. FIXME"); - long t2 = Clock.getInstance().now(); + long t2 = _context.clock().now(); BigInteger aalpha = new NativeBigInteger(1, publicKey.getData()); - long t3 = Clock.getInstance().now(); + long t3 = _context.clock().now(); BigInteger yk[] = getNextYK(); BigInteger k = yk[1]; BigInteger y = yk[0]; - long t7 = Clock.getInstance().now(); + long t7 = _context.clock().now(); BigInteger d = aalpha.modPow(k, CryptoConstants.elgp); - long t8 = Clock.getInstance().now(); + long t8 = _context.clock().now(); d = d.multiply(m); - long t9 = Clock.getInstance().now(); + long t9 = _context.clock().now(); d = d.mod(CryptoConstants.elgp); - long t10 = Clock.getInstance().now(); + long t10 = _context.clock().now(); byte[] ybytes = y.toByteArray(); byte[] dbytes = d.toByteArray(); @@ -146,14 +150,14 @@ public class ElGamalEngine { buf.append("8-9: ").append(t9 - t8).append('\n'); buf.append("9-10: ").append(t10 - t9).append('\n'); //_log.debug(buf.toString()); - long end = Clock.getInstance().now(); + long end = _context.clock().now(); long diff = end - start; if (diff > 1000) { if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to encrypt ElGamal block (" + diff + "ms)"); } - StatManager.getInstance().addRateData("crypto.elGamal.encrypt", diff, diff); + _context.statManager().addRateData("crypto.elGamal.encrypt", diff, diff); return out; } @@ -165,7 +169,7 @@ public class ElGamalEngine { public byte[] decrypt(byte encrypted[], PrivateKey privateKey) { if ((encrypted == null) || (encrypted.length > 514)) throw new IllegalArgumentException("Data to decrypt must be <= 514 bytes at the moment"); - long start = Clock.getInstance().now(); + long start = _context.clock().now(); byte[] ybytes = new byte[257]; byte[] dbytes = new byte[257]; @@ -196,10 +200,10 @@ public class ElGamalEngine { return null; } - Hash calcHash = SHA256Generator.getInstance().calculateHash(rv); + Hash calcHash = _context.sha().calculateHash(rv); boolean ok = calcHash.equals(hash); - long end = Clock.getInstance().now(); + long end = _context.clock().now(); long diff = end - start; if (diff > 1000) { @@ -207,7 +211,7 @@ public class ElGamalEngine { _log.warn("Took too long to decrypt and verify ElGamal block (" + diff + "ms)"); } - StatManager.getInstance().addRateData("crypto.elGamal.decrypt", diff, diff); + _context.statManager().addRateData("crypto.elGamal.decrypt", diff, diff); if (ok) { //_log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length)); @@ -236,6 +240,7 @@ public class ElGamalEngine { } RandomSource.getInstance().nextBoolean(); + I2PAppContext context = new I2PAppContext(); System.out.println("Running " + numRuns + " times"); @@ -249,9 +254,9 @@ public class ElGamalEngine { byte buf[] = new byte[128]; RandomSource.getInstance().nextBytes(buf); long startE = Clock.getInstance().now(); - byte encr[] = ElGamalEngine.getInstance().encrypt(buf, pubkey); + byte encr[] = context.elGamalEngine().encrypt(buf, pubkey); long endE = Clock.getInstance().now(); - byte decr[] = ElGamalEngine.getInstance().decrypt(encr, privkey); + byte decr[] = context.elGamalEngine().decrypt(encr, privkey); long endD = Clock.getInstance().now(); eTime += endE - startE; dTime += endD - endE; @@ -259,8 +264,7 @@ public class ElGamalEngine { if (!DataHelper.eq(decr, buf)) { System.out.println("PublicKey : " + DataHelper.toString(pubkey.getData(), pubkey.getData().length)); - System.out.println("PrivateKey : " - + DataHelper.toString(privkey.getData(), privkey.getData().length)); + System.out.println("PrivateKey : " + DataHelper.toString(privkey.getData(), privkey.getData().length)); System.out.println("orig : " + DataHelper.toString(buf, buf.length)); System.out.println("d(e(orig) : " + DataHelper.toString(decr, decr.length)); System.out.println("orig.len : " + buf.length); diff --git a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java b/core/java/src/net/i2p/crypto/HMACSHA256Generator.java index 62bbc1060..c6ff13cf5 100644 --- a/core/java/src/net/i2p/crypto/HMACSHA256Generator.java +++ b/core/java/src/net/i2p/crypto/HMACSHA256Generator.java @@ -3,28 +3,23 @@ package net.i2p.crypto; import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.SessionKey; +import net.i2p.I2PAppContext; /** * Calculate the HMAC-SHA256 of a key+message. Currently FAKE - returns a stupid * kludgy hash: H(H(key) XOR H(data)). Fix me! * */ -public abstract class HMACSHA256Generator { - private static HMACSHA256Generator _generator = new DummyHMACSHA256Generator(); - +public class HMACSHA256Generator { + public HMACSHA256Generator(I2PAppContext context) {}; public static HMACSHA256Generator getInstance() { - return _generator; + return I2PAppContext.getGlobalContext().hmac(); } - - public abstract Hash calculate(SessionKey key, byte data[]); -} - -/** - * jrandom smells. - * - */ - -class DummyHMACSHA256Generator extends HMACSHA256Generator { + + /** + * This should calculate the HMAC/SHA256, but it DOESNT. Its just a kludge. + * Fix me. + */ public Hash calculate(SessionKey key, byte data[]) { if ((key == null) || (key.getData() == null) || (data == null)) throw new NullPointerException("Null arguments for HMAC"); diff --git a/core/java/src/net/i2p/crypto/KeyGenerator.java b/core/java/src/net/i2p/crypto/KeyGenerator.java index fecb44048..9327242fe 100644 --- a/core/java/src/net/i2p/crypto/KeyGenerator.java +++ b/core/java/src/net/i2p/crypto/KeyGenerator.java @@ -22,18 +22,24 @@ import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.NativeBigInteger; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** Define a way of generating asymetrical key pairs as well as symetrical keys * @author jrandom */ public class KeyGenerator { - private final static Log _log = new Log(KeyGenerator.class); - private static final RandomSource _random = RandomSource.getInstance(); - private static KeyGenerator _generator = new KeyGenerator(); + private Log _log; + private I2PAppContext _context; - public static KeyGenerator getInstance() { - return _generator; + public KeyGenerator(I2PAppContext context) { + _log = context.logManager().getLog(KeyGenerator.class); + _context = context; } + public static KeyGenerator getInstance() { + return I2PAppContext.getGlobalContext().keyGenerator(); + } + + /** Generate a private 256 bit session key * @return session key @@ -42,7 +48,7 @@ public class KeyGenerator { // 256bit random # as a session key SessionKey key = new SessionKey(); byte data[] = new byte[SessionKey.KEYSIZE_BYTES]; - _random.nextBytes(data); + _context.random().nextBytes(data); key.setData(data); return key; } @@ -52,7 +58,7 @@ public class KeyGenerator { * @return pair of keys */ public Object[] generatePKIKeypair() { - BigInteger a = new NativeBigInteger(2048, _random); + BigInteger a = new NativeBigInteger(2048, _context.random()); BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp); Object[] keys = new Object[2]; @@ -80,7 +86,7 @@ public class KeyGenerator { // make sure the random key is less than the DSA q do { - x = new NativeBigInteger(160, _random); + x = new NativeBigInteger(160, _context.random()); } while (x.compareTo(CryptoConstants.dsaq) >= 0); BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap); @@ -118,13 +124,14 @@ public class KeyGenerator { byte src[] = new byte[200]; RandomSource.getInstance().nextBytes(src); + I2PAppContext ctx = new I2PAppContext(); long time = 0; for (int i = 0; i < 10; i++) { long start = Clock.getInstance().now(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); long end = Clock.getInstance().now(); - byte ctext[] = ElGamalEngine.getInstance().encrypt(src, (PublicKey) keys[0]); - byte ptext[] = ElGamalEngine.getInstance().decrypt(ctext, (PrivateKey) keys[1]); + byte ctext[] = ctx.elGamalEngine().encrypt(src, (PublicKey) keys[0]); + byte ptext[] = ctx.elGamalEngine().decrypt(ctext, (PrivateKey) keys[1]); time += end - start; if (DataHelper.eq(ptext, src)) log.debug("D(E(data)) == data"); diff --git a/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java b/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java index 5c88e9edd..291002683 100644 --- a/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/PersistentSessionKeyManager.java @@ -27,6 +27,7 @@ import net.i2p.data.PublicKey; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Expose the functionality to allow people to write out and read in the @@ -39,6 +40,19 @@ public class PersistentSessionKeyManager extends TransientSessionKeyManager { private Object _yk = YKGenerator.class; + + /** + * The session key manager should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + public PersistentSessionKeyManager(I2PAppContext context) { + super(context); + } + private PersistentSessionKeyManager() { + super(null); + } /** * Write the session key data to the given stream * @@ -146,7 +160,8 @@ public class PersistentSessionKeyManager extends TransientSessionKeyManager { } public static void main(String args[]) { - PersistentSessionKeyManager mgr = new PersistentSessionKeyManager(); + I2PAppContext ctx = new I2PAppContext(); + PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)ctx.sessionKeyManager(); try { mgr.loadState(new FileInputStream("sessionKeys.dat")); String state = mgr.renderStatusHTML(); diff --git a/core/java/src/net/i2p/crypto/SHA256Generator.java b/core/java/src/net/i2p/crypto/SHA256Generator.java index 2ed42a12d..683c5d166 100644 --- a/core/java/src/net/i2p/crypto/SHA256Generator.java +++ b/core/java/src/net/i2p/crypto/SHA256Generator.java @@ -30,6 +30,7 @@ package net.i2p.crypto; */ import net.i2p.data.Hash; +import net.i2p.I2PAppContext; /** Defines a wrapper for SHA-256 operation * @@ -38,10 +39,9 @@ import net.i2p.data.Hash; * @author thecrypto,jrandom */ public class SHA256Generator { - private static SHA256Generator _generator = new SHA256Generator(); - + public SHA256Generator(I2PAppContext context) {}; public static SHA256Generator getInstance() { - return _generator; + return I2PAppContext.getGlobalContext().sha(); } static int[] K = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, diff --git a/core/java/src/net/i2p/crypto/SessionKeyManager.java b/core/java/src/net/i2p/crypto/SessionKeyManager.java index cdbd91152..ee3073041 100644 --- a/core/java/src/net/i2p/crypto/SessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/SessionKeyManager.java @@ -14,6 +14,7 @@ import java.util.Set; import net.i2p.data.PublicKey; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; +import net.i2p.I2PAppContext; /** * Manage the session keys and session tags used for encryption and decryption. @@ -23,12 +24,11 @@ import net.i2p.data.SessionTag; * */ public class SessionKeyManager { - private final static SessionKeyManager _instance = new PersistentSessionKeyManager(); // new TransientSessionKeyManager(); // SessionKeyManager(); - - public final static SessionKeyManager getInstance() { - return _instance; - } - + /** session key managers must be created through an app context */ + protected SessionKeyManager(I2PAppContext context) {} + /** see above */ + private SessionKeyManager() {} + /** * Retrieve the session key currently associated with encryption to the target, * or null if a new session key should be generated. diff --git a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java index 33109e6d0..72e06fa8a 100644 --- a/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java +++ b/core/java/src/net/i2p/crypto/TransientSessionKeyManager.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.data.PublicKey; import net.i2p.data.SessionKey; @@ -52,11 +53,18 @@ class TransientSessionKeyManager extends SessionKeyManager { public final static long SESSION_LIFETIME_MAX_MS = SESSION_TAG_DURATION_MS + 5 * 60 * 1000; public final static int MAX_INBOUND_SESSION_TAGS = 100 * 1000; // this will consume at most 3.2M - public TransientSessionKeyManager() { - super(); + /** + * The session key manager should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + public TransientSessionKeyManager(I2PAppContext context) { + super(context); _outboundSessions = new HashMap(64); _inboundTagSets = new HashMap(1024); } + private TransientSessionKeyManager() { super(null); } /** TagSet */ protected Set getInboundTagSets() { diff --git a/core/java/src/net/i2p/crypto/YKGenerator.java b/core/java/src/net/i2p/crypto/YKGenerator.java index c97a76e48..d5be31834 100644 --- a/core/java/src/net/i2p/crypto/YKGenerator.java +++ b/core/java/src/net/i2p/crypto/YKGenerator.java @@ -18,6 +18,7 @@ import net.i2p.util.I2PThread; import net.i2p.util.Log; import net.i2p.util.NativeBigInteger; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Precalculate the Y and K for ElGamal encryption operations. @@ -56,22 +57,23 @@ class YKGenerator { private final static long CHECK_DELAY = 30 * 1000; static { + I2PAppContext ctx = I2PAppContext.getGlobalContext(); try { - int val = Integer.parseInt(System.getProperty(PROP_YK_PRECALC_MIN, DEFAULT_YK_PRECALC_MIN)); + 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(System.getProperty(PROP_YK_PRECALC_MAX, DEFAULT_YK_PRECALC_MAX)); + 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(System.getProperty(PROP_YK_PRECALC_DELAY, DEFAULT_YK_PRECALC_DELAY)); + 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); diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 78dfe0485..8a13ebb09 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -35,7 +35,6 @@ import net.i2p.util.OrderedProperties; * @author jrandom */ public class DataHelper { - private final static Log _log = new Log(DataHelper.class); private final static String _equal = "="; // in UTF-8 private final static String _semicolon = ";"; // in UTF-8 @@ -56,7 +55,8 @@ public class DataHelper { * @throws IOException if there is a problem reading the data * @return mapping */ - public static Properties readProperties(InputStream rawStream) throws DataFormatException, IOException { + public static Properties readProperties(InputStream rawStream) + throws DataFormatException, IOException { Properties props = new OrderedProperties(); long size = readLong(rawStream, 2); byte data[] = new byte[(int) size]; @@ -65,24 +65,18 @@ public class DataHelper { ByteArrayInputStream in = new ByteArrayInputStream(data); byte eqBuf[] = _equal.getBytes(); byte semiBuf[] = _semicolon.getBytes(); - try { - while (in.available() > 0) { - String key = readString(in); - read = read(in, eqBuf); - if ((read != eqBuf.length) || (!eq(new String(eqBuf), _equal))) { - _log.debug("Failed eqtest [" + new String(eqBuf) + "]"); - break; - } - String val = readString(in); - read = read(in, semiBuf); - if ((read != semiBuf.length) || (!eq(new String(semiBuf), _semicolon))) { - _log.debug("Failed semitest [" + new String(semiBuf) + "]"); - break; - } - props.put(key, val); + while (in.available() > 0) { + String key = readString(in); + read = read(in, eqBuf); + if ((read != eqBuf.length) || (!eq(new String(eqBuf), _equal))) { + break; } - } catch (IOException ioe) { - _log.warn("Error reading properties", ioe); + String val = readString(in); + read = read(in, semiBuf); + if ((read != semiBuf.length) || (!eq(new String(semiBuf), _semicolon))) { + break; + } + props.put(key, val); } return props; } @@ -96,8 +90,8 @@ public class DataHelper { * @throws DataFormatException if there is not enough valid data to write out * @throws IOException if there is an IO error writing out the data */ - public static void writeProperties(OutputStream rawStream, Properties props) throws DataFormatException, - IOException { + public static void writeProperties(OutputStream rawStream, Properties props) + throws DataFormatException, IOException { OrderedProperties p = new OrderedProperties(); if (props != null) p.putAll(props); ByteArrayOutputStream baos = new ByteArrayOutputStream(32); @@ -204,10 +198,10 @@ public class DataHelper { * @throws IOException if there is an IO error reading the number * @return number */ - public static long readLong(InputStream rawStream, int numBytes) throws DataFormatException, IOException { + public static long readLong(InputStream rawStream, int numBytes) + throws DataFormatException, IOException { if (numBytes > 8) - throw new DataFormatException( - "readLong doesn't currently support reading numbers > 8 bytes [as thats bigger than java's long]"); + throw new DataFormatException("readLong doesn't currently support reading numbers > 8 bytes [as thats bigger than java's long]"); byte data[] = new byte[numBytes]; int num = read(rawStream, data); if (num != numBytes) @@ -225,8 +219,8 @@ public class DataHelper { * @throws DataFormatException if the stream doesn't contain a validly formatted number of that many bytes * @throws IOException if there is an IO error writing to the stream */ - public static void writeLong(OutputStream rawStream, int numBytes, long value) throws DataFormatException, - IOException { + public static void writeLong(OutputStream rawStream, int numBytes, long value) + throws DataFormatException, IOException { UnsignedInteger i = new UnsignedInteger(value); rawStream.write(i.getBytes(numBytes)); } @@ -254,7 +248,8 @@ public class DataHelper { * @throws DataFormatException if the date is not valid * @throws IOException if there is an IO error writing the date */ - public static void writeDate(OutputStream out, Date date) throws DataFormatException, IOException { + public static void writeDate(OutputStream out, Date date) + throws DataFormatException, IOException { if (date == null) writeLong(out, 8, 0L); else @@ -286,7 +281,8 @@ public class DataHelper { * @throws DataFormatException if the string is not valid * @throws IOException if there is an IO error writing the string */ - public static void writeString(OutputStream out, String string) throws DataFormatException, IOException { + public static void writeString(OutputStream out, String string) + throws DataFormatException, IOException { if (string == null) { writeLong(out, 1, 0); } else { @@ -328,7 +324,8 @@ public class DataHelper { * @throws DataFormatException if the boolean is not valid * @throws IOException if there is an IO error writing the boolean */ - public static void writeBoolean(OutputStream out, Boolean bool) throws DataFormatException, IOException { + public static void writeBoolean(OutputStream out, Boolean bool) + throws DataFormatException, IOException { if (bool == null) writeLong(out, 1, 2); else if (Boolean.TRUE.equals(bool)) @@ -353,7 +350,6 @@ public class DataHelper { boolean eq = (((lhs == null) && (rhs == null)) || ((lhs != null) && (lhs.equals(rhs)))); return eq; } catch (ClassCastException cce) { - _log.warn("Error comparing [" + lhs + "] with [" + rhs + "]", cce); return false; } } @@ -542,12 +538,12 @@ public class DataHelper { out.finish(); out.flush(); byte rv[] = baos.toByteArray(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Compression of " + orig.length + " into " + rv.length + " (or " + 100.0d - * (((double) orig.length) / ((double) rv.length)) + "% savings)"); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Compression of " + orig.length + " into " + rv.length + " (or " + 100.0d + // * (((double) orig.length) / ((double) rv.length)) + "% savings)"); return rv; } catch (IOException ioe) { - _log.error("Error compressing?!", ioe); + //_log.error("Error compressing?!", ioe); return null; } } @@ -565,12 +561,12 @@ public class DataHelper { baos.write(buf, 0, read); } byte rv[] = baos.toByteArray(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Decompression of " + orig.length + " into " + rv.length + " (or " + 100.0d - * (((double) rv.length) / ((double) orig.length)) + "% savings)"); + //if (_log.shouldLog(Log.DEBUG)) + // _log.debug("Decompression of " + orig.length + " into " + rv.length + " (or " + 100.0d + // * (((double) rv.length) / ((double) orig.length)) + "% savings)"); return rv; } catch (IOException ioe) { - _log.error("Error decompressing?", ioe); + //_log.error("Error decompressing?", ioe); return null; } } diff --git a/core/java/src/net/i2p/data/RoutingKeyGenerator.java b/core/java/src/net/i2p/data/RoutingKeyGenerator.java index 5b549e2b8..b0f270c89 100644 --- a/core/java/src/net/i2p/data/RoutingKeyGenerator.java +++ b/core/java/src/net/i2p/data/RoutingKeyGenerator.java @@ -19,6 +19,7 @@ import net.i2p.crypto.SHA256Generator; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Component to manage the munging of hashes into routing keys - given a hash, @@ -40,12 +41,17 @@ import net.i2p.util.RandomSource; * */ public class RoutingKeyGenerator { - private final static RoutingKeyGenerator _instance = new RoutingKeyGenerator(); + private Log _log; + private I2PAppContext _context; - public static RoutingKeyGenerator getInstance() { - return _instance; + public RoutingKeyGenerator(I2PAppContext context) { + _log = context.logManager().getLog(RoutingKeyGenerator.class); + _context = context; } - private final static Log _log = new Log(RoutingKeyGenerator.class); + public static RoutingKeyGenerator getInstance() { + return I2PAppContext.getGlobalContext().routingKeyGenerator(); + } + private byte _currentModData[]; private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT")); @@ -67,7 +73,7 @@ public class RoutingKeyGenerator { public void generateDateBasedModData() { Date today = null; synchronized (_cal) { - _cal.setTime(new Date(Clock.getInstance().now())); + _cal.setTime(new Date(_context.clock().now())); _cal.set(Calendar.HOUR_OF_DAY, 0); _cal.set(Calendar.MINUTE, 0); _cal.set(Calendar.SECOND, 0); diff --git a/core/java/src/net/i2p/stat/SimpleStatDumper.java b/core/java/src/net/i2p/stat/SimpleStatDumper.java index f4cecd395..e53edcaec 100644 --- a/core/java/src/net/i2p/stat/SimpleStatDumper.java +++ b/core/java/src/net/i2p/stat/SimpleStatDumper.java @@ -6,24 +6,25 @@ import java.util.Set; import java.util.TreeSet; import net.i2p.util.Log; +import net.i2p.I2PAppContext; public class SimpleStatDumper { private final static Log _log = new Log(SimpleStatDumper.class); - public static void dumpStats(int logLevel) { + public static void dumpStats(I2PAppContext context, int logLevel) { if (!_log.shouldLog(logLevel)) return; StringBuffer buf = new StringBuffer(4 * 1024); - dumpFrequencies(buf); - dumpRates(buf); + dumpFrequencies(context, buf); + dumpRates(context, buf); _log.log(logLevel, buf.toString()); } - private static void dumpFrequencies(StringBuffer buf) { - Set frequencies = new TreeSet(StatManager.getInstance().getFrequencyNames()); + private static void dumpFrequencies(I2PAppContext ctx, StringBuffer buf) { + Set frequencies = new TreeSet(ctx.statManager().getFrequencyNames()); for (Iterator iter = frequencies.iterator(); iter.hasNext();) { String name = (String) iter.next(); - FrequencyStat freq = StatManager.getInstance().getFrequency(name); + FrequencyStat freq = ctx.statManager().getFrequency(name); buf.append('\n'); buf.append(freq.getGroupName()).append('.').append(freq.getName()).append(": ") .append(freq.getDescription()).append('\n'); @@ -39,11 +40,11 @@ public class SimpleStatDumper { } } - private static void dumpRates(StringBuffer buf) { - Set rates = new TreeSet(StatManager.getInstance().getRateNames()); + private static void dumpRates(I2PAppContext ctx, StringBuffer buf) { + Set rates = new TreeSet(ctx.statManager().getRateNames()); for (Iterator iter = rates.iterator(); iter.hasNext();) { String name = (String) iter.next(); - RateStat rate = StatManager.getInstance().getRate(name); + RateStat rate = ctx.statManager().getRate(name); buf.append('\n'); buf.append(rate.getGroupName()).append('.').append(rate.getName()).append(": ") .append(rate.getDescription()).append('\n'); diff --git a/core/java/src/net/i2p/stat/StatManager.java b/core/java/src/net/i2p/stat/StatManager.java index 1ef3f9c61..72ea06823 100644 --- a/core/java/src/net/i2p/stat/StatManager.java +++ b/core/java/src/net/i2p/stat/StatManager.java @@ -10,6 +10,7 @@ import java.util.TreeMap; import java.util.TreeSet; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Coordinate the management of various frequencies and rates within I2P components, @@ -19,18 +20,23 @@ import net.i2p.util.Log; * */ public class StatManager { - private final static Log _log = new Log(StatManager.class); - private final static StatManager _instance = new StatManager(); + private Log _log; + private I2PAppContext _context; - public final static StatManager getInstance() { - return _instance; - } /** stat name to FrequencyStat */ private Map _frequencyStats; /** stat name to RateStat */ private Map _rateStats; - private StatManager() { + /** + * The stat manager should only be constructed and accessed through the + * application context. This constructor should only be used by the + * appropriate application context itself. + * + */ + public StatManager(I2PAppContext context) { + _log = context.logManager().getLog(StatManager.class); + _context = context; _frequencyStats = Collections.synchronizedMap(new HashMap(128)); _rateStats = Collections.synchronizedMap(new HashMap(128)); } @@ -44,6 +50,7 @@ public class StatManager { * @param periods array of period lengths (in milliseconds) */ public void createFrequencyStat(String name, String description, String group, long periods[]) { + if (_frequencyStats.containsKey(name)) return; _frequencyStats.put(name, new FrequencyStat(name, description, group, periods)); } @@ -56,6 +63,7 @@ public class StatManager { * @param periods array of period lengths (in milliseconds) */ public void createRateStat(String name, String description, String group, long periods[]) { + if (_rateStats.containsKey(name)) return; _rateStats.put(name, new RateStat(name, description, group, periods)); } diff --git a/core/java/src/net/i2p/util/Clock.java b/core/java/src/net/i2p/util/Clock.java index 9cd2ca368..834834fc1 100644 --- a/core/java/src/net/i2p/util/Clock.java +++ b/core/java/src/net/i2p/util/Clock.java @@ -4,6 +4,8 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import net.i2p.I2PAppContext; + /** * Alternate location for determining the time which takes into account an offset. * This offset will ideally be periodically updated so as to serve as the difference @@ -12,12 +14,20 @@ import java.util.Set; * */ public class Clock { - private final static Log _log = new Log(Clock.class); - private final static Clock _instance = new Clock(); - - public final static Clock getInstance() { - return _instance; + private I2PAppContext _context; + public Clock(I2PAppContext context) { + _context = context; + _offset = 0; + _alreadyChanged = false; + _listeners = new HashSet(64); } + public static Clock getInstance() { + return I2PAppContext.getGlobalContext().clock(); + } + + /** we fetch it on demand to avoid circular dependencies (logging uses the clock) */ + private Log getLog() { return _context.logManager().getLog(Clock.class); } + private volatile long _offset; private boolean _alreadyChanged; private Set _listeners; @@ -27,12 +37,6 @@ public class Clock { /** if the clock skewed changes by less than 1s, ignore the update (so we don't slide all over the place) */ public final static long MIN_OFFSET_CHANGE = 30 * 1000; - private Clock() { - _offset = 0; - _alreadyChanged = false; - _listeners = new HashSet(64); - } - /** * Specify how far away from the "correct" time the computer is - a positive * value means that we are slow, while a negative value means we are fast. @@ -40,18 +44,18 @@ public class Clock { */ public void setOffset(long offsetMs) { if ((offsetMs > MAX_OFFSET) || (offsetMs < 0 - MAX_OFFSET)) { - _log.error("Maximum offset shift exceeded [" + offsetMs + "], NOT HONORING IT"); + getLog().error("Maximum offset shift exceeded [" + offsetMs + "], NOT HONORING IT"); return; } long delta = offsetMs - _offset; if ((delta < MIN_OFFSET_CHANGE) && (delta > 0 - MIN_OFFSET_CHANGE)) { - _log.debug("Not changing offset since it is only " + delta + "ms"); + getLog().debug("Not changing offset since it is only " + delta + "ms"); return; } if (_alreadyChanged) - _log.log(Log.CRIT, "Updating clock offset to " + offsetMs + "ms from " + _offset + "ms"); + getLog().log(Log.CRIT, "Updating clock offset to " + offsetMs + "ms from " + _offset + "ms"); else - _log.log(Log.INFO, "Initializing clock offset to " + offsetMs + "ms from " + _offset + "ms"); + getLog().log(Log.INFO, "Initializing clock offset to " + offsetMs + "ms from " + _offset + "ms"); _alreadyChanged = true; _offset = offsetMs; fireOffsetChanged(delta); diff --git a/core/java/src/net/i2p/util/Log.java b/core/java/src/net/i2p/util/Log.java index ab2dfe94a..151ccd478 100644 --- a/core/java/src/net/i2p/util/Log.java +++ b/core/java/src/net/i2p/util/Log.java @@ -9,6 +9,9 @@ package net.i2p.util; * */ +import net.i2p.data.DataHelper; +import net.i2p.I2PAppContext; + /** * Wrapper class for whatever logging system I2P uses. This class should be * instantiated and kept as a variable for each class it is used by, ala: @@ -24,6 +27,8 @@ public class Log { private Class _class; private String _name; private int _minPriority; + private LogScope _scope; + private LogManager _manager; public final static int DEBUG = 10; public final static int INFO = 20; @@ -65,33 +70,46 @@ public class Log { } public Log(Class cls) { - this(cls, null); + this(I2PAppContext.getGlobalContext().logManager(), cls, null); + _manager.addLog(this); } public Log(String name) { - this(null, name); + this(I2PAppContext.getGlobalContext().logManager(), null, name); + _manager.addLog(this); } - public Log(Class cls, String name) { + Log(LogManager manager, Class cls) { + this(manager, cls, null); + } + + Log(LogManager manager, String name) { + this(manager, null, name); + } + + Log(LogManager manager, Class cls, String name) { + _manager = manager; _class = cls; _name = name; _minPriority = DEBUG; - LogManager.getInstance().registerLog(this); + _scope = new LogScope(name, cls); + //_manager.addRecord(new LogRecord(Log.class, null, Thread.currentThread().getName(), Log.DEBUG, + // "Log created with manager " + manager + " for class " + cls, null)); } public void log(int priority, String msg) { if (priority >= _minPriority) { - LogManager.getInstance().addRecord( - new LogRecord(_class, _name, Thread.currentThread().getName(), priority, - msg, null)); + _manager.addRecord(new LogRecord(_class, _name, + Thread.currentThread().getName(), priority, + msg, null)); } } public void log(int priority, String msg, Throwable t) { if (priority >= _minPriority) { - LogManager.getInstance().addRecord( - new LogRecord(_class, _name, Thread.currentThread().getName(), priority, - msg, t)); + _manager.addRecord(new LogRecord(_class, _name, + Thread.currentThread().getName(), priority, + msg, t)); } } @@ -133,6 +151,9 @@ public class Log { public void setMinimumPriority(int priority) { _minPriority = priority; + //_manager.addRecord(new LogRecord(Log.class, null, Thread.currentThread().getName(), Log.DEBUG, + // "Log with manager " + _manager + " for class " + _class + // + " new priority " + toLevelString(priority), null)); } public boolean shouldLog(int priority) { @@ -145,5 +166,32 @@ public class Log { else return _name; } - + + public Object getScope() { return _scope; } + private static final class LogScope { + private String _scopeName; + private Class _scopeClass; + public LogScope(String name, Class cls) { + _scopeName = name; + _scopeClass = cls; + } + public int hashCode() { + if (_scopeClass != null) + return _scopeClass.hashCode(); + else if (_scopeName != null) + return _scopeName.hashCode(); + else + return 42; + } + public boolean equals(Object obj) { + if (obj == null) throw new NullPointerException("Null object scope?"); + if (obj instanceof LogScope) { + LogScope s = (LogScope)obj; + return DataHelper.eq(s._scopeName, _scopeName) && + DataHelper.eq(s._scopeClass, _scopeClass); + } else { + return false; + } + } + } } \ No newline at end of file diff --git a/core/java/src/net/i2p/util/LogConsoleBuffer.java b/core/java/src/net/i2p/util/LogConsoleBuffer.java index c5b4e88c1..296034823 100644 --- a/core/java/src/net/i2p/util/LogConsoleBuffer.java +++ b/core/java/src/net/i2p/util/LogConsoleBuffer.java @@ -1,26 +1,24 @@ package net.i2p.util; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.List; +import net.i2p.I2PAppContext; /** * Offer a glimpse into the last few console messages generated * */ public class LogConsoleBuffer { - private final static LogConsoleBuffer _instance = new LogConsoleBuffer(); - - public final static LogConsoleBuffer getInstance() { - return _instance; - } + private I2PAppContext _context; private List _buffer; - private LogConsoleBuffer() { - _buffer = new LinkedList(); + public LogConsoleBuffer(I2PAppContext context) { + _context = context; + _buffer = new ArrayList(); } void add(String msg) { - int lim = LogManager.getInstance().getConsoleBufferSize(); + int lim = _context.logManager().getConsoleBufferSize(); synchronized (_buffer) { while (_buffer.size() >= lim) _buffer.remove(0); @@ -36,7 +34,7 @@ public class LogConsoleBuffer { */ public List getMostRecentMessages() { synchronized (_buffer) { - return new LinkedList(_buffer); + return new ArrayList(_buffer); } } } \ No newline at end of file diff --git a/core/java/src/net/i2p/util/LogManager.java b/core/java/src/net/i2p/util/LogManager.java index 55f1104e2..01aee4614 100644 --- a/core/java/src/net/i2p/util/LogManager.java +++ b/core/java/src/net/i2p/util/LogManager.java @@ -19,6 +19,10 @@ import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; +import java.util.Map; +import java.util.HashMap; + +import net.i2p.I2PAppContext; /** * Manages the logging system, loading (and reloading) the configuration file, @@ -31,14 +35,6 @@ public class LogManager { public final static String CONFIG_LOCATION_PROP = "loggerConfigLocation"; public final static String FILENAME_OVERRIDE_PROP = "loggerFilenameOverride"; public final static String CONFIG_LOCATION_DEFAULT = "logger.config"; - - public static final LogManager getInstance() { - return _instance; - } - private static final LogManager _instance = new LogManager(System.getProperty(CONFIG_LOCATION_PROP, - CONFIG_LOCATION_DEFAULT)); - private static final Log _log = new Log(LogManager.class); - /** * These define the characters in the format line of the config file */ @@ -65,12 +61,15 @@ public class LogManager { public final static String DEFAULT_DEFALTLEVEL = Log.STR_DEBUG; public final static String DEFAULT_ONSCREENLEVEL = Log.STR_DEBUG; + private I2PAppContext _context; + private Log _log; + private long _configLastRead; private String _location; private List _records; private Set _limits; - private Set _logs; + private Map _logs; private LogWriter _writer; private int _defaultLimit; @@ -83,7 +82,59 @@ public class LogManager { private boolean _displayOnScreen; private int _consoleBufferSize; + + private LogConsoleBuffer _consoleBuffer; + public LogManager(I2PAppContext context) { + _displayOnScreen = true; + _records = new ArrayList(); + _limits = new HashSet(); + _logs = new HashMap(128); + _defaultLimit = Log.DEBUG; + _configLastRead = 0; + _location = context.getProperty(CONFIG_LOCATION_PROP, CONFIG_LOCATION_DEFAULT); + _context = context; + _log = getLog(LogManager.class); + _consoleBuffer = new LogConsoleBuffer(context); + loadConfig(); + _writer = new LogWriter(this); + Thread t = new I2PThread(_writer); + t.setName("LogWriter"); + t.setDaemon(true); + t.start(); + Runtime.getRuntime().addShutdownHook(new ShutdownHook()); + System.out.println("Created logManager " + this + " with context: " + context); + } + private LogManager() {} + + public Log getLog(Class cls) { return getLog(cls, null); } + public Log getLog(String name) { return getLog(null, name); } + public Log getLog(Class cls, String name) { + Log rv = null; + synchronized (_logs) { + Log newLog = new Log(this, cls, name); + if (_logs.containsKey(newLog.getScope())) { + Log oldLog = (Log)_logs.get(newLog.getScope()); + rv = oldLog; + //_log.error("Duplicate log creation for " + cls); + } else { + _logs.put(newLog.getScope(), newLog); + rv = newLog; + } + } + updateLimit(rv); + return rv; + } + void addLog(Log log) { + synchronized (_logs) { + if (!_logs.containsKey(log.getScope())) + _logs.put(log.getScope(), log); + } + updateLimit(log); + } + + public LogConsoleBuffer getBuffer() { return _consoleBuffer; } + public void setDisplayOnScreen(boolean yes) { _displayOnScreen = yes; } @@ -123,18 +174,7 @@ public class LogManager { _records.add(record); } } - - /** - * Called during Log construction - * - */ - void registerLog(Log log) { - synchronized (_logs) { - _logs.add(log); - } - updateLimit(log); - } - + /** * Called periodically by the log writer's thread * @@ -148,23 +188,6 @@ public class LogManager { /// /// - private LogManager(String location) { - _displayOnScreen = true; - _location = location; - _records = new ArrayList(); - _limits = new HashSet(); - _logs = new HashSet(); - _defaultLimit = Log.DEBUG; - _configLastRead = 0; - loadConfig(); - _writer = new LogWriter(); - Thread t = new I2PThread(_writer); - t.setName("LogWriter"); - t.setDaemon(true); - t.start(); - Runtime.getRuntime().addShutdownHook(new ShutdownHook()); - } - // // // @@ -175,6 +198,8 @@ public class LogManager { if ((_configLastRead > 0) && (_configLastRead > cfgFile.lastModified())) { _log.debug("Short circuiting config read"); return; + } else { + _log.debug("Loading config from " + _location); } FileInputStream fis = null; try { @@ -212,7 +237,7 @@ public class LogManager { _displayOnScreen = false; } - String filenameOverride = System.getProperty(FILENAME_OVERRIDE_PROP); + String filenameOverride = _context.getProperty(FILENAME_OVERRIDE_PROP); if (filenameOverride != null) _baseLogfilename = filenameOverride; else @@ -297,11 +322,11 @@ public class LogManager { } private void updateLimits() { - Set logs = new HashSet(); + Map logs = null; synchronized (_logs) { - logs.addAll(_logs); + logs = new HashMap(_logs); } - for (Iterator iter = logs.iterator(); iter.hasNext();) { + for (Iterator iter = logs.values().iterator(); iter.hasNext();) { Log log = (Log) iter.next(); updateLimit(log); } @@ -322,10 +347,13 @@ public class LogManager { } } } - if (max != null) + if (max != null) { log.setMinimumPriority(max.getLimit()); - else + } else { + //if (_log != null) + // _log.debug("The log for " + log.getClass() + " has no matching limits"); log.setMinimumPriority(_defaultLimit); + } } private List getLimits(Log log) { @@ -373,10 +401,11 @@ public class LogManager { } public static void main(String args[]) { - Log l1 = new Log("test.1"); - Log l2 = new Log("test.2"); - Log l21 = new Log("test.2.1"); - Log l = new Log("test"); + I2PAppContext ctx = new I2PAppContext(); + Log l1 = ctx.logManager().getLog("test.1"); + Log l2 = ctx.logManager().getLog("test.2"); + Log l21 = ctx.logManager().getLog("test.2.1"); + Log l = ctx.logManager().getLog("test"); l.debug("this should fail"); l.info("this should pass"); l1.warn("this should pass"); diff --git a/core/java/src/net/i2p/util/LogRecordFormatter.java b/core/java/src/net/i2p/util/LogRecordFormatter.java index b186e7e10..52ce0426e 100644 --- a/core/java/src/net/i2p/util/LogRecordFormatter.java +++ b/core/java/src/net/i2p/util/LogRecordFormatter.java @@ -26,13 +26,13 @@ class LogRecordFormatter { private final static int MAX_THREAD_LENGTH = 12; private final static int MAX_PRIORITY_LENGTH = 5; - public static String formatRecord(LogRecord rec) { + public static String formatRecord(LogManager manager, LogRecord rec) { StringBuffer buf = new StringBuffer(); - char format[] = LogManager.getInstance()._getFormat(); + char format[] = manager._getFormat(); for (int i = 0; i < format.length; ++i) { switch ((int) format[i]) { case (int) LogManager.DATE: - buf.append(getWhen(rec)); + buf.append(getWhen(manager, rec)); break; case (int) LogManager.CLASS: buf.append(getWhere(rec)); @@ -71,8 +71,8 @@ class LogRecordFormatter { return toString(logRecord.getThreadName(), MAX_THREAD_LENGTH); } - private static String getWhen(LogRecord logRecord) { - return LogManager.getInstance()._getDateFormat().format(new Date(logRecord.getDate())); + private static String getWhen(LogManager manager, LogRecord logRecord) { + return manager._getDateFormat().format(new Date(logRecord.getDate())); } private static String getPriority(LogRecord rec) { diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java index 19eca261a..1dd472aac 100644 --- a/core/java/src/net/i2p/util/LogWriter.java +++ b/core/java/src/net/i2p/util/LogWriter.java @@ -29,8 +29,14 @@ class LogWriter implements Runnable { private int _rotationNum = -1; private String _logFilenamePattern; private File _currentFile; + private LogManager _manager; private boolean _write; + + private LogWriter() {} + public LogWriter(LogManager manager) { + _manager = manager; + } public void stopWriting() { _write = false; @@ -46,7 +52,7 @@ class LogWriter implements Runnable { public void flushRecords() { try { - List records = LogManager.getInstance()._removeAll(); + List records = _manager._removeAll(); for (int i = 0; i < records.size(); i++) { LogRecord rec = (LogRecord) records.get(i); writeRecord(rec); @@ -68,19 +74,19 @@ class LogWriter implements Runnable { } long now = Clock.getInstance().now(); if (now - _lastReadConfig > CONFIG_READ_ITERVAL) { - LogManager.getInstance().rereadConfig(); + _manager.rereadConfig(); _lastReadConfig = now; } } private void writeRecord(LogRecord rec) { - String val = LogRecordFormatter.formatRecord(rec); + String val = LogRecordFormatter.formatRecord(_manager, rec); writeRecord(val); - if (LogManager.getInstance().getDisplayOnScreenLevel() <= rec.getPriority()) { + if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) { // we always add to the console buffer, but only sometimes write to stdout - LogConsoleBuffer.getInstance().add(val); - if (LogManager.getInstance().displayOnScreen()) { + _manager.getBuffer().add(val); + if (_manager.displayOnScreen()) { System.out.print(val); } } @@ -98,7 +104,7 @@ class LogWriter implements Runnable { System.err.println("Error writing record, disk full?"); t.printStackTrace(); } - if (_numBytesInCurrentFile >= LogManager.getInstance()._getFileSize()) { + if (_numBytesInCurrentFile >= _manager._getFileSize()) { rotateFile(); } } @@ -108,7 +114,7 @@ class LogWriter implements Runnable { * */ private void rotateFile() { - String pattern = LogManager.getInstance()._getBaseLogfilename(); + String pattern = _manager._getBaseLogfilename(); File f = getNextFile(pattern); _currentFile = f; _numBytesInCurrentFile = 0; @@ -129,7 +135,7 @@ class LogWriter implements Runnable { if (pattern.indexOf('#') < 0) { return new File(pattern); } else { - int max = LogManager.getInstance()._getRotationLimit(); + int max = _manager._getRotationLimit(); if (_rotationNum == -1) { return getFirstFile(pattern, max); } else { diff --git a/core/java/src/net/i2p/util/RandomSource.java b/core/java/src/net/i2p/util/RandomSource.java index 3929bac1b..648d0a69f 100644 --- a/core/java/src/net/i2p/util/RandomSource.java +++ b/core/java/src/net/i2p/util/RandomSource.java @@ -10,6 +10,7 @@ package net.i2p.util; */ import java.security.SecureRandom; +import net.i2p.I2PAppContext; /** * Singleton for whatever PRNG i2p uses. @@ -17,14 +18,14 @@ import java.security.SecureRandom; * @author jrandom */ public class RandomSource extends SecureRandom { - private final static RandomSource _random = new RandomSource(); + private Log _log; - private RandomSource() { + public RandomSource(I2PAppContext context) { super(); + _log = context.logManager().getLog(RandomSource.class); } - public static RandomSource getInstance() { - return _random; + return I2PAppContext.getGlobalContext().random(); } /** diff --git a/core/java/test/net/i2p/crypto/AES256Bench.java b/core/java/test/net/i2p/crypto/AES256Bench.java index 05718e4f2..60cce7cdf 100644 --- a/core/java/test/net/i2p/crypto/AES256Bench.java +++ b/core/java/test/net/i2p/crypto/AES256Bench.java @@ -1,138 +1,140 @@ package net.i2p.crypto; -/* +/* * Copyright (c) 2003, TheCrypto * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without + * + * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this + * + * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * - Neither the name of the TheCrypto may be used to endorse or promote - * products derived from this software without specific prior written + * - Neither the name of the TheCrypto may be used to endorse or promote + * products derived from this software without specific prior written * permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import net.i2p.data.SessionKey; import net.i2p.data.DataHelper; +import net.i2p.I2PAppContext; public class AES256Bench { - + private static I2PAppContext _context = new I2PAppContext(); + public static void main(String args[]) { - char[] cplain = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff - }; - - byte[] plain = new byte[cplain.length]; - for (int x = 0; x < cplain.length; x++) { - plain[x] = (byte)cplain[x]; - } - char[] ckey = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f - }; - byte[] bkey = new byte[ckey.length]; - for (int x = 0; x < ckey.length; x++) { - bkey[x] = (byte)ckey[x]; - } - - SessionKey key = new SessionKey(); - key.setData(bkey); - - char[] civ = { - 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, - 0xfe, 0xdc, 0xba, 0x98, 0x67, 0x54, 0x32, 0x10 - }; - - byte[] iv = new byte[civ.length]; - for (int x = 0; x < iv.length; x++) { - iv[x] = (byte)civ[x]; - } - - byte[] e = AESEngine.getInstance().encrypt(plain, key, iv); - byte[] d = AESEngine.getInstance().decrypt(e, key, iv); - boolean same = true; - for (int x = 0; x < d.length; x++) { - if (plain[x] != d[x]) { - same = false; - } - } - - System.out.println("Standard test D(E(value)) == value? " + same); - - plain = "1234567890123456".getBytes(); - e = AESEngine.getInstance().encrypt(plain, key, iv); - d = AESEngine.getInstance().decrypt(e, key, iv); - same = DataHelper.eq(plain, d); - System.out.println("Different value test D(E(value)) == value? " + same); - - System.out.println(); - System.out.println(); - - long times = 100; - long encrypttime = 0; - long decrypttime = 0; - long maxE = 0; - long minE = 0; - long maxD = 0; - long minD = 0; - byte[] message = new byte[2*1024]; - for (int i = 0; i < message.length; i++) - message[i] = (byte)((i%26)+'a'); - for (int x = 0; x < times; x++) { - long startencrypt = System.currentTimeMillis(); - e = AESEngine.getInstance().encrypt(message, key, iv); - long endencryptstartdecrypt = System.currentTimeMillis(); - d = AESEngine.getInstance().decrypt(e, key, iv); - long enddecrypt = System.currentTimeMillis(); - System.out.print("."); - encrypttime += endencryptstartdecrypt - startencrypt; - decrypttime += enddecrypt - endencryptstartdecrypt; - if (!DataHelper.eq(d, message)) { - System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]"); - System.out.println("Data: dest [" + DataHelper.toString(d, d.length) + "]"); - throw new RuntimeException("Holy crap, decrypted != source message"); - } - - if ( (minE == 0) && (minD == 0) ) { - minE = endencryptstartdecrypt - startencrypt; - maxE = endencryptstartdecrypt - startencrypt; - minD = enddecrypt - endencryptstartdecrypt; - maxD = enddecrypt - endencryptstartdecrypt; - } else { - if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt; - if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt; - if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt; - if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt; - } - - } - - System.out.println(); - System.out.println("Data size : " + message.length); - System.out.println("Encryption Time Average : " + (encrypttime/times) + "ms\ttotal: " + encrypttime + "ms\tmin: " + minE + "ms\tmax: " + maxE + "ms\tEncryption Bps: " + (times*message.length*1000)/encrypttime); - System.out.println("Decryption Time Average : " + (decrypttime/times) + "ms\ttotal: " + decrypttime + "ms\tmin: " + minD + "ms\tmax: " + maxD + "ms\tDecryption Bps: " + (times*message.length*1000)/decrypttime); + char[] cplain = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff + }; + + byte[] plain = new byte[cplain.length]; + for (int x = 0; x < cplain.length; x++) { + plain[x] = (byte)cplain[x]; + } + char[] ckey = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f + }; + byte[] bkey = new byte[ckey.length]; + for (int x = 0; x < ckey.length; x++) { + bkey[x] = (byte)ckey[x]; + } + + SessionKey key = new SessionKey(); + key.setData(bkey); + + char[] civ = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x67, 0x54, 0x32, 0x10 + }; + + byte[] iv = new byte[civ.length]; + for (int x = 0; x < iv.length; x++) { + iv[x] = (byte)civ[x]; + } + + byte[] e = _context.AESEngine().encrypt(plain, key, iv); + byte[] d = _context.AESEngine().decrypt(e, key, iv); + boolean same = true; + for (int x = 0; x < d.length; x++) { + if (plain[x] != d[x]) { + same = false; + } + } + + System.out.println("Standard test D(E(value)) == value? " + same); + + plain = "1234567890123456".getBytes(); + e = _context.AESEngine().encrypt(plain, key, iv); + d = _context.AESEngine().decrypt(e, key, iv); + same = DataHelper.eq(plain, d); + System.out.println("Different value test D(E(value)) == value? " + same); + + System.out.println(); + System.out.println(); + + long times = 100; + long encrypttime = 0; + long decrypttime = 0; + long maxE = 0; + long minE = 0; + long maxD = 0; + long minD = 0; + byte[] message = new byte[2*1024]; + for (int i = 0; i < message.length; i++) + message[i] = (byte)((i%26)+'a'); + for (int x = 0; x < times; x++) { + long startencrypt = System.currentTimeMillis(); + e = _context.AESEngine().encrypt(message, key, iv); + long endencryptstartdecrypt = System.currentTimeMillis(); + d = _context.AESEngine().decrypt(e, key, iv); + long enddecrypt = System.currentTimeMillis(); + System.out.print("."); + encrypttime += endencryptstartdecrypt - startencrypt; + decrypttime += enddecrypt - endencryptstartdecrypt; + if (!DataHelper.eq(d, message)) { + System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]"); + System.out.println("Data: dest [" + DataHelper.toString(d, d.length) + "]"); + throw new RuntimeException("Holy crap, decrypted != source message"); + } + + if ( (minE == 0) && (minD == 0) ) { + minE = endencryptstartdecrypt - startencrypt; + maxE = endencryptstartdecrypt - startencrypt; + minD = enddecrypt - endencryptstartdecrypt; + maxD = enddecrypt - endencryptstartdecrypt; + } else { + if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt; + if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt; + if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt; + if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt; + } + + } + + System.out.println(); + System.out.println("Data size : " + message.length); + System.out.println("Encryption Time Average : " + (encrypttime/times) + "ms\ttotal: " + encrypttime + "ms\tmin: " + minE + "ms\tmax: " + maxE + "ms\tEncryption Bps: " + (times*message.length*1000)/encrypttime); + System.out.println("Decryption Time Average : " + (decrypttime/times) + "ms\ttotal: " + decrypttime + "ms\tmin: " + minD + "ms\tmax: " + maxD + "ms\tDecryption Bps: " + (times*message.length*1000)/decrypttime); } } - + diff --git a/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java b/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java index afe2548aa..9fc0a0a05 100644 --- a/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java +++ b/core/java/test/net/i2p/crypto/ElGamalAESEngineTest.java @@ -1,13 +1,14 @@ 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 + * 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 net.i2p.I2PAppContext; import net.i2p.data.Hash; import net.i2p.data.SessionKey; import net.i2p.data.PublicKey; @@ -25,211 +26,216 @@ import java.util.HashSet; class ElGamalAESEngineTest { private final static Log _log = new Log(ElGamalAESEngineTest.class); - public void runRoundtripTest() { - try { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - - String msg = "Hello world"; - Set toBeDelivered = new HashSet(); - SessionKey key = SessionKeyManager.getInstance().getCurrentKey(pubKey); - if (key == null) - key = SessionKeyManager.getInstance().createSession(pubKey); - byte[] encrypted = ElGamalAESEngine.encrypt(msg.getBytes(), pubKey, key, 64); - byte[] decrypted = ElGamalAESEngine.decrypt(encrypted, privKey); - if (decrypted == null) - throw new Exception("Failed to decrypt"); - String read = new String(decrypted); - _log.debug("read: " + read); - _log.debug("Match? " + msg.equals(read)); - } catch (Exception e) { - _log.error("Error", e); - try { Thread.sleep(5000); } catch (InterruptedException ie) {} - System.exit(0); - } + private I2PAppContext _context; + public ElGamalAESEngineTest(I2PAppContext ctx) { + _context = ctx; } - + public void runRoundtripTest() { + try { + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + + String msg = "Hello world"; + Set toBeDelivered = new HashSet(); + SessionKey key = _context.sessionKeyManager().getCurrentKey(pubKey); + if (key == null) + key = _context.sessionKeyManager().createSession(pubKey); + byte[] encrypted = _context.elGamalAESEngine().encrypt(msg.getBytes(), pubKey, key, 64); + byte[] decrypted = _context.elGamalAESEngine().decrypt(encrypted, privKey); + if (decrypted == null) + throw new Exception("Failed to decrypt"); + String read = new String(decrypted); + _log.debug("read: " + read); + _log.debug("Match? " + msg.equals(read)); + } catch (Exception e) { + _log.error("Error", e); + try { Thread.sleep(5000); } catch (InterruptedException ie) {} + System.exit(0); + } + } + public void runLoopTest(int runs) { - try { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - - long e0 = 0; - long d0 = 0; - long eTot = 0; - long dTot = 0; - for (int i = 0; i < runs; i++) { - long times[] = runMessage(pubKey, privKey); - _log.debug("E[" + i + "] time: " + times[0] + "ms"); - _log.debug("D["+i+"] time: " + times[1] + "ms"); - if (i == 0) { - e0 = times[0]; - d0 = times[1]; - } - eTot += times[0]; - dTot += times[1]; - } - _log.debug("E average time: " + eTot/runs + "ms"); - _log.debug("D average time: " + dTot/runs + "ms"); - _log.debug("Total time to send and receive " + (runs) + "Kb: " + (eTot+dTot)+"ms"); - - } catch (Exception e) { - _log.error("Error", e); - try { Thread.sleep(5000); } catch (InterruptedException ie) {} - System.exit(0); - } + try { + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + + long e0 = 0; + long d0 = 0; + long eTot = 0; + long dTot = 0; + for (int i = 0; i < runs; i++) { + long times[] = runMessage(pubKey, privKey); + _log.debug("E[" + i + "] time: " + times[0] + "ms"); + _log.debug("D["+i+"] time: " + times[1] + "ms"); + if (i == 0) { + e0 = times[0]; + d0 = times[1]; + } + eTot += times[0]; + dTot += times[1]; + } + _log.debug("E average time: " + eTot/runs + "ms"); + _log.debug("D average time: " + dTot/runs + "ms"); + _log.debug("Total time to send and receive " + (runs) + "Kb: " + (eTot+dTot)+"ms"); + + } catch (Exception e) { + _log.error("Error", e); + try { Thread.sleep(5000); } catch (InterruptedException ie) {} + System.exit(0); + } } private long[] runMessage(PublicKey pubKey, PrivateKey privKey) throws Exception { - byte[] msg = new byte[400]; - RandomSource.getInstance().nextBytes(msg); - SessionKey key = SessionKeyManager.getInstance().getCurrentKey(pubKey); - if (key == null) - key = SessionKeyManager.getInstance().createSession(pubKey); - - long beforeE = Clock.getInstance().now(); - byte[] encrypted = ElGamalAESEngine.encrypt(msg, pubKey, key, 1024); - long afterE = Clock.getInstance().now(); - byte[] decrypted = ElGamalAESEngine.decrypt(encrypted, privKey); - long afterD = Clock.getInstance().now(); - if (!DataHelper.eq(msg, decrypted)) { - _log.error("WTF, D(E(val)) != val"); - return null; - } - - long rv[] = new long[2]; - rv[0] = afterE - beforeE; - rv[1] = afterD - afterE; - return rv; + byte[] msg = new byte[400]; + RandomSource.getInstance().nextBytes(msg); + SessionKey key = _context.sessionKeyManager().getCurrentKey(pubKey); + if (key == null) + key = _context.sessionKeyManager().createSession(pubKey); + + long beforeE = Clock.getInstance().now(); + byte[] encrypted = _context.elGamalAESEngine().encrypt(msg, pubKey, key, 1024); + long afterE = Clock.getInstance().now(); + byte[] decrypted = _context.elGamalAESEngine().decrypt(encrypted, privKey); + long afterD = Clock.getInstance().now(); + if (!DataHelper.eq(msg, decrypted)) { + _log.error("WTF, D(E(val)) != val"); + return null; + } + + long rv[] = new long[2]; + rv[0] = afterE - beforeE; + rv[1] = afterD - afterE; + return rv; } public void runAESTest() { - try { - SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey(); - Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); - byte iv[] = new byte[16]; - System.arraycopy(h.getData(), 0, iv, 0, 16); - - String msg = "Hello world"; - - byte encrypted[] = ElGamalAESEngine.encryptAESBlock(msg.getBytes(), sessionKey, iv, null, null, 64); - _log.debug("** Encryption complete. Beginning decryption"); - Set foundTags = new HashSet(); - SessionKey foundKey = new SessionKey(); - byte decrypted[] = ElGamalAESEngine.decryptAESBlock(encrypted, sessionKey, iv, null, foundTags, foundKey); - if (decrypted == null) throw new Exception("Decryption failed"); - String read = new String(decrypted); - _log.debug("read: " + read); - _log.debug("Match? " + msg.equals(read)); - } catch (Exception e) { - _log.error("Error", e); - try { Thread.sleep(5000); } catch (InterruptedException ie) {} - System.exit(0); - } + try { + SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey(); + Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); + byte iv[] = new byte[16]; + System.arraycopy(h.getData(), 0, iv, 0, 16); + + String msg = "Hello world"; + + byte encrypted[] = _context.elGamalAESEngine().encryptAESBlock(msg.getBytes(), sessionKey, iv, null, null, 64); + _log.debug("** Encryption complete. Beginning decryption"); + Set foundTags = new HashSet(); + SessionKey foundKey = new SessionKey(); + byte decrypted[] = _context.elGamalAESEngine().decryptAESBlock(encrypted, sessionKey, iv, null, foundTags, foundKey); + if (decrypted == null) throw new Exception("Decryption failed"); + String read = new String(decrypted); + _log.debug("read: " + read); + _log.debug("Match? " + msg.equals(read)); + } catch (Exception e) { + _log.error("Error", e); + try { Thread.sleep(5000); } catch (InterruptedException ie) {} + System.exit(0); + } } public void runBasicAESTest() { - try { - SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey(); - Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); - byte iv[] = new byte[16]; - System.arraycopy(h.getData(), 0, iv, 0, 16); - - String msg = "Hello world01234012345678901234501234567890123450123456789012345"; - h = SHA256Generator.getInstance().calculateHash(msg.getBytes()); - _log.debug("Hash of entire aes block before encryption: \n" + DataHelper.toString(h.getData(), 32)); - byte aesEncr[] = AESEngine.getInstance().encrypt(msg.getBytes(), sessionKey, iv); - byte aesDecr[] = AESEngine.getInstance().decrypt(aesEncr, sessionKey, iv); - h = SHA256Generator.getInstance().calculateHash(aesDecr); - _log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); - if (msg.equals(new String(aesDecr))) { - _log.debug("**AES Basic test passed!\n\n"); - } - } catch (Exception e) { - _log.error("Error", e); - try { Thread.sleep(5000); } catch (InterruptedException ie) {} - System.exit(0); - } + try { + SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey(); + Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); + byte iv[] = new byte[16]; + System.arraycopy(h.getData(), 0, iv, 0, 16); + + String msg = "Hello world01234012345678901234501234567890123450123456789012345"; + h = SHA256Generator.getInstance().calculateHash(msg.getBytes()); + _log.debug("Hash of entire aes block before encryption: \n" + DataHelper.toString(h.getData(), 32)); + byte aesEncr[] = _context.AESEngine().encrypt(msg.getBytes(), sessionKey, iv); + byte aesDecr[] = _context.AESEngine().decrypt(aesEncr, sessionKey, iv); + h = SHA256Generator.getInstance().calculateHash(aesDecr); + _log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); + if (msg.equals(new String(aesDecr))) { + _log.debug("**AES Basic test passed!\n\n"); + } + } catch (Exception e) { + _log.error("Error", e); + try { Thread.sleep(5000); } catch (InterruptedException ie) {} + System.exit(0); + } } public void runElGamalTest(int numLoops) { - - for (int i = 0; i < numLoops; i++) { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - SessionKey key = KeyGenerator.getInstance().generateSessionKey(); - - runBasicElGamalTest(key, pubKey, privKey); - } + + for (int i = 0; i < numLoops; i++) { + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + SessionKey key = KeyGenerator.getInstance().generateSessionKey(); + + runBasicElGamalTest(key, pubKey, privKey); + } } public void runBasicElGamalTest(SessionKey key, PublicKey pubKey, PrivateKey privKey) { - try { - ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(256); - key.writeBytes(elgSrc); - byte preIV[] = new byte[32]; - RandomSource.getInstance().nextBytes(preIV); - elgSrc.write(preIV); -// byte rnd[] = new byte[191]; -// RandomSource.getInstance().nextBytes(rnd); -// elgSrc.write(rnd); - elgSrc.flush(); - - byte elgEncr[] = ElGamalEngine.getInstance().encrypt(elgSrc.toByteArray(), pubKey); - byte elgDecr[] = ElGamalEngine.getInstance().decrypt(elgEncr, privKey); - - ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr); - SessionKey nk = new SessionKey(); - - nk.readBytes(bais); - byte postpreIV[] = new byte[32]; - int read = bais.read(postpreIV); - if (read != postpreIV.length) { - // hmm, this can't really happen... - throw new Exception("Somehow ElGamal broke and 256 bytes is less than 32 bytes..."); - } - // ignore the next 192 bytes - boolean eq = (DataHelper.eq(preIV, postpreIV) && DataHelper.eq(key, nk)); - if (!eq) { - _log.error("elgEncr.length: " + elgEncr.length + " elgDecr.length: " + elgDecr.length); - _log.error("Pre IV.................: " + DataHelper.toString(preIV, 32)); - _log.error("Pre IV after decryption: " + DataHelper.toString(postpreIV, 32)); - _log.error("SessionKey.................: " + DataHelper.toString(key.getData(), 32)); - _log.error("SessionKey after decryption: " + DataHelper.toString(nk.getData(), 32)); - _log.error("PublicKey: " + DataHelper.toDecimalString(pubKey.getData(), pubKey.getData().length)); - _log.error("PrivateKey: " + DataHelper.toDecimalString(privKey.getData(), privKey.getData().length)); - - throw new Exception("Not equal!"); - } else { - _log.debug("Basic ElG D(E(val)) == val"); - } - - } catch (Exception e) { - _log.error("Error", e); - try { Thread.sleep(5000); } catch (InterruptedException ie) {} - System.exit(0); - } + try { + ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(256); + key.writeBytes(elgSrc); + byte preIV[] = new byte[32]; + RandomSource.getInstance().nextBytes(preIV); + elgSrc.write(preIV); + // byte rnd[] = new byte[191]; + // RandomSource.getInstance().nextBytes(rnd); + // elgSrc.write(rnd); + elgSrc.flush(); + + byte elgEncr[] = _context.elGamalEngine().encrypt(elgSrc.toByteArray(), pubKey); + byte elgDecr[] = _context.elGamalEngine().decrypt(elgEncr, privKey); + + ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr); + SessionKey nk = new SessionKey(); + + nk.readBytes(bais); + byte postpreIV[] = new byte[32]; + int read = bais.read(postpreIV); + if (read != postpreIV.length) { + // hmm, this can't really happen... + throw new Exception("Somehow ElGamal broke and 256 bytes is less than 32 bytes..."); + } + // ignore the next 192 bytes + boolean eq = (DataHelper.eq(preIV, postpreIV) && DataHelper.eq(key, nk)); + if (!eq) { + _log.error("elgEncr.length: " + elgEncr.length + " elgDecr.length: " + elgDecr.length); + _log.error("Pre IV.................: " + DataHelper.toString(preIV, 32)); + _log.error("Pre IV after decryption: " + DataHelper.toString(postpreIV, 32)); + _log.error("SessionKey.................: " + DataHelper.toString(key.getData(), 32)); + _log.error("SessionKey after decryption: " + DataHelper.toString(nk.getData(), 32)); + _log.error("PublicKey: " + DataHelper.toDecimalString(pubKey.getData(), pubKey.getData().length)); + _log.error("PrivateKey: " + DataHelper.toDecimalString(privKey.getData(), privKey.getData().length)); + + throw new Exception("Not equal!"); + } else { + _log.debug("Basic ElG D(E(val)) == val"); + } + + } catch (Exception e) { + _log.error("Error", e); + try { Thread.sleep(5000); } catch (InterruptedException ie) {} + System.exit(0); + } } public static void main(String args[]) { - ElGamalAESEngineTest tst = new ElGamalAESEngineTest(); - Object o = YKGenerator.class; - try { Thread.sleep(120*1000); } catch (InterruptedException ie) {} - - tst.runBasicAESTest(); - tst.runAESTest(); - tst.runRoundtripTest(); - tst.runElGamalTest(2); - // test bug - for (int i = 0; i < 3; i++) - tst.runLoopTest(1); - // test throughput - tst.runLoopTest(5); - - net.i2p.stat.SimpleStatDumper.dumpStats(Log.CRIT); - try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} + I2PAppContext context = new I2PAppContext(); + ElGamalAESEngineTest tst = new ElGamalAESEngineTest(context); + Object o = YKGenerator.class; + try { Thread.sleep(120*1000); } catch (InterruptedException ie) {} + + tst.runBasicAESTest(); + tst.runAESTest(); + tst.runRoundtripTest(); + tst.runElGamalTest(2); + // test bug + for (int i = 0; i < 3; i++) + tst.runLoopTest(1); + // test throughput + tst.runLoopTest(5); + + net.i2p.stat.SimpleStatDumper.dumpStats(context, Log.CRIT); + try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} } } diff --git a/core/java/test/net/i2p/crypto/ElGamalBench.java b/core/java/test/net/i2p/crypto/ElGamalBench.java index 64ca0aa84..92728674e 100644 --- a/core/java/test/net/i2p/crypto/ElGamalBench.java +++ b/core/java/test/net/i2p/crypto/ElGamalBench.java @@ -1,96 +1,98 @@ package net.i2p.crypto; -/* +/* * Copyright (c) 2003, TheCrypto * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without + * + * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this + * + * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. - * - Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. - * - Neither the name of the TheCrypto may be used to endorse or promote - * products derived from this software without specific prior written + * - Neither the name of the TheCrypto may be used to endorse or promote + * products derived from this software without specific prior written * permission. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ import net.i2p.data.DataHelper; import net.i2p.data.PrivateKey; import net.i2p.data.PublicKey; +import net.i2p.I2PAppContext; public class ElGamalBench { - public static void main(String args[]) { - int times = 100; - long keygentime = 0; - long encrypttime = 0; - long decrypttime = 0; - long maxKey = 0; - long minKey = 0; - long maxE = 0; - long minE = 0; - long maxD = 0; - long minD = 0; - Object[] keys = KeyGenerator.getInstance().generatePKIKeypair(); - byte[] message = new byte[222]; - for (int i = 0; i < message.length; i++) - message[i] = (byte)((i%26)+'a'); - for (int x = 0; x < times; x++) { - long startkeys = System.currentTimeMillis(); - keys = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubkey = (PublicKey)keys[0]; - PrivateKey privkey = (PrivateKey)keys[1]; - long endkeys = System.currentTimeMillis(); - long startencrypt = System.currentTimeMillis(); - byte[] e = ElGamalEngine.getInstance().encrypt(message, pubkey); - long endencryptstartdecrypt = System.currentTimeMillis(); - byte[] d = ElGamalEngine.getInstance().decrypt(e, privkey); - long enddecrypt = System.currentTimeMillis(); - System.out.print("."); - keygentime += endkeys - startkeys; - encrypttime += endencryptstartdecrypt - startencrypt; - decrypttime += enddecrypt - endencryptstartdecrypt; - if (!DataHelper.eq(d, message)) { - System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]"); - byte hash1[] = SHA256Generator.getInstance().calculateHash(message).getData(); - byte hash2[] = SHA256Generator.getInstance().calculateHash(d).getData(); - System.out.println("Hashes: source [" + DataHelper.toString(hash1, hash1.length) + "] dest [" + DataHelper.toString(hash2, hash2.length) + "]"); - throw new RuntimeException("Holy crap, decrypted != source message"); - } - if ( (minKey == 0) && (minE == 0) && (minD == 0) ) { - minKey = endkeys - startkeys; - maxKey = endkeys - startkeys; - minE = endencryptstartdecrypt - startencrypt; - maxE = endencryptstartdecrypt - startencrypt; - minD = enddecrypt - endencryptstartdecrypt; - maxD = enddecrypt - endencryptstartdecrypt; - } else { - if (minKey > endkeys - startkeys) minKey = endkeys - startkeys; - if (maxKey < endkeys - startkeys) maxKey = endkeys - startkeys; - if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt; - if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt; - if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt; - if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt; - } - } - System.out.println(); - System.out.println("Key Generation Time Average: " + (keygentime/times) + "\ttotal: " + keygentime + "\tmin: " + minKey + "\tmax: " + maxKey + "\tKeygen/second: " + (keygentime == 0 ? "NaN" : ""+(times*1000)/keygentime)); - System.out.println("Encryption Time Average : " + (encrypttime/times) + "\ttotal: " + encrypttime + "\tmin: " + minE + "\tmax: " + maxE + "\tEncryption Bps: " + (times*message.length*1000)/encrypttime); - System.out.println("Decryption Time Average : " + (decrypttime/times) + "\ttotal: " + decrypttime + "\tmin: " + minD + "\tmax: " + maxD + "\tDecryption Bps: " + (times*message.length*1000)/decrypttime); - } + private static I2PAppContext _context = new I2PAppContext(); + public static void main(String args[]) { + int times = 100; + long keygentime = 0; + long encrypttime = 0; + long decrypttime = 0; + long maxKey = 0; + long minKey = 0; + long maxE = 0; + long minE = 0; + long maxD = 0; + long minD = 0; + Object[] keys = KeyGenerator.getInstance().generatePKIKeypair(); + byte[] message = new byte[222]; + for (int i = 0; i < message.length; i++) + message[i] = (byte)((i%26)+'a'); + for (int x = 0; x < times; x++) { + long startkeys = System.currentTimeMillis(); + keys = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubkey = (PublicKey)keys[0]; + PrivateKey privkey = (PrivateKey)keys[1]; + long endkeys = System.currentTimeMillis(); + long startencrypt = System.currentTimeMillis(); + byte[] e = _context.elGamalEngine().encrypt(message, pubkey); + long endencryptstartdecrypt = System.currentTimeMillis(); + byte[] d = _context.elGamalEngine().decrypt(e, privkey); + long enddecrypt = System.currentTimeMillis(); + System.out.print("."); + keygentime += endkeys - startkeys; + encrypttime += endencryptstartdecrypt - startencrypt; + decrypttime += enddecrypt - endencryptstartdecrypt; + if (!DataHelper.eq(d, message)) { + System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]"); + byte hash1[] = SHA256Generator.getInstance().calculateHash(message).getData(); + byte hash2[] = SHA256Generator.getInstance().calculateHash(d).getData(); + System.out.println("Hashes: source [" + DataHelper.toString(hash1, hash1.length) + "] dest [" + DataHelper.toString(hash2, hash2.length) + "]"); + throw new RuntimeException("Holy crap, decrypted != source message"); + } + if ( (minKey == 0) && (minE == 0) && (minD == 0) ) { + minKey = endkeys - startkeys; + maxKey = endkeys - startkeys; + minE = endencryptstartdecrypt - startencrypt; + maxE = endencryptstartdecrypt - startencrypt; + minD = enddecrypt - endencryptstartdecrypt; + maxD = enddecrypt - endencryptstartdecrypt; + } else { + if (minKey > endkeys - startkeys) minKey = endkeys - startkeys; + if (maxKey < endkeys - startkeys) maxKey = endkeys - startkeys; + if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt; + if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt; + if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt; + if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt; + } + } + System.out.println(); + System.out.println("Key Generation Time Average: " + (keygentime/times) + "\ttotal: " + keygentime + "\tmin: " + minKey + "\tmax: " + maxKey + "\tKeygen/second: " + (keygentime == 0 ? "NaN" : ""+(times*1000)/keygentime)); + System.out.println("Encryption Time Average : " + (encrypttime/times) + "\ttotal: " + encrypttime + "\tmin: " + minE + "\tmax: " + maxE + "\tEncryption Bps: " + (times*message.length*1000)/encrypttime); + System.out.println("Decryption Time Average : " + (decrypttime/times) + "\ttotal: " + decrypttime + "\tmin: " + minD + "\tmax: " + maxD + "\tDecryption Bps: " + (times*message.length*1000)/decrypttime); + } } - + diff --git a/core/java/test/net/i2p/crypto/SessionEncryptionTest.java b/core/java/test/net/i2p/crypto/SessionEncryptionTest.java index 5a1364e55..a6ed0fdaf 100644 --- a/core/java/test/net/i2p/crypto/SessionEncryptionTest.java +++ b/core/java/test/net/i2p/crypto/SessionEncryptionTest.java @@ -1,9 +1,9 @@ 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 + * 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. * */ @@ -16,6 +16,7 @@ import net.i2p.data.DataHelper; import net.i2p.util.Log; import net.i2p.util.Clock; +import net.i2p.I2PAppContext; import java.util.HashSet; import java.util.Set; @@ -24,383 +25,384 @@ import java.util.Set; * * session key management unit tests: * - * Run tagsIncluded useTag rekey + * Run tagsIncluded useTag rekey * // no sessions - * 1 no no no - * 2 no no no + * 1 no no no + * 2 no no no * // session - * 3 yes (2) no no - * 4 no yes no - * 5 yes (2) yes no - * 6 no yes no - * 7 no yes no + * 3 yes (2) no no + * 4 no yes no + * 5 yes (2) yes no + * 6 no yes no + * 7 no yes no * // rekeying - * 8 yes (2) no no - * 9 no yes no - * 10 yes (2) yes yes - * 11 no yes no - * 12 no yes no + * 8 yes (2) no no + * 9 no yes no + * 10 yes (2) yes yes + * 11 no yes no + * 12 no yes no * // long session - * 13-1000 20 tags every 10 messages, rekey every 50 + * 13-1000 20 tags every 10 messages, rekey every 50 */ public class SessionEncryptionTest { private final static Log _log = new Log(SessionEncryptionTest.class); + private static I2PAppContext _context = new I2PAppContext(); public static void main(String args[]) { - SessionEncryptionTest test = new SessionEncryptionTest(); - try { - //test.testNoSessions(); - //test.testSessions(); - //test.testRekeying(); - test.testLongSession(); - } catch (Throwable t) { - _log.error("Error running tests", t); - } - try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} + SessionEncryptionTest test = new SessionEncryptionTest(); + try { + //test.testNoSessions(); + //test.testSessions(); + //test.testRekeying(); + test.testLongSession(); + } catch (Throwable t) { + _log.error("Error running tests", t); + } + try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} } - + /** - * Run tagsIncluded useTag rekey - * 1 no no no - * 2 no no no + * Run tagsIncluded useTag rekey + * 1 no no no + * 2 no no no */ public void testNoSessions() throws Exception { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); - - byte[] msg1 = "msg 1".getBytes(); - byte[] msg2 = "msg 2".getBytes(); - - byte emsg1[] = ElGamalAESEngine.encrypt(msg1, pubKey, curKey, 64); - byte dmsg1[] = ElGamalAESEngine.decrypt(emsg1, privKey); - if (DataHelper.eq(dmsg1, msg1)) - _log.info("PASSED: No sessions msg 1"); - else - _log.error("FAILED: No sessions msg 1"); - - byte emsg2[] = ElGamalAESEngine.encrypt(msg2, pubKey, curKey, 64); - byte dmsg2[] = ElGamalAESEngine.decrypt(emsg2, privKey); - if (DataHelper.eq(dmsg2, msg2)) - _log.info("PASSED: No sessions msg 2"); - else - _log.error("FAILED: No sessions msg 2"); - } - + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + SessionKey curKey = _context.sessionKeyManager().createSession(pubKey); + + byte[] msg1 = "msg 1".getBytes(); + byte[] msg2 = "msg 2".getBytes(); + + byte emsg1[] = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, 64); + byte dmsg1[] = _context.elGamalAESEngine().decrypt(emsg1, privKey); + if (DataHelper.eq(dmsg1, msg1)) + _log.info("PASSED: No sessions msg 1"); + else + _log.error("FAILED: No sessions msg 1"); + + byte emsg2[] = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, 64); + byte dmsg2[] = _context.elGamalAESEngine().decrypt(emsg2, privKey); + if (DataHelper.eq(dmsg2, msg2)) + _log.info("PASSED: No sessions msg 2"); + else + _log.error("FAILED: No sessions msg 2"); + } + /** - * Run tagsIncluded useTag rekey - * 1 yes (2) no no - * 2 no yes no - * 3 yes (2) yes no - * 4 no yes no - * 5 no yes no + * Run tagsIncluded useTag rekey + * 1 yes (2) no no + * 2 no yes no + * 3 yes (2) yes no + * 4 no yes no + * 5 no yes no */ public void testSessions() throws Exception { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); - - SessionTag tag1 = new SessionTag(true); - SessionTag tag2 = new SessionTag(true); - SessionTag tag3 = new SessionTag(true); - SessionTag tag4 = new SessionTag(true); - - HashSet firstTags = new HashSet(); - firstTags.add(tag1); - firstTags.add(tag2); - - HashSet secondTags = new HashSet(); - secondTags.add(tag3); - secondTags.add(tag4); - - byte[] msg1 = "msg 1".getBytes(); - byte[] msg2 = "msg 2".getBytes(); - byte[] msg3 = "msg 3".getBytes(); - byte[] msg4 = "msg 4".getBytes(); - byte[] msg5 = "msg 5".getBytes(); - - byte emsg1[] = ElGamalAESEngine.encrypt(msg1, pubKey, curKey, firstTags, 64); - byte dmsg1[] = ElGamalAESEngine.decrypt(emsg1, privKey); - if (DataHelper.eq(dmsg1, msg1)) - _log.info("PASSED: Sessions msg 1"); - else { - _log.error("FAILED: Sessions msg 1"); - return; - } - - SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, firstTags); - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - SessionTag curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - if (curTag == null) { - _log.error("Not able to consume next tag for message 2"); - return; - } - - byte emsg2[] = ElGamalAESEngine.encrypt(msg2, pubKey, curKey, null, curTag, 64); - byte dmsg2[] = ElGamalAESEngine.decrypt(emsg2, privKey); - if (DataHelper.eq(dmsg2, msg2)) - _log.info("PASSED: Sessions msg 2"); - else { - _log.error("FAILED: Sessions msg 2"); - return; - } - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - if (curTag == null) { - _log.error("Not able to consume next tag for message 3"); - return; - } - if (curKey == null) { - _log.error("Not able to consume next KEY for message 3"); - return; - } - - byte emsg3[] = ElGamalAESEngine.encrypt(msg3, pubKey, curKey, secondTags, curTag, 64); - byte dmsg3[] = ElGamalAESEngine.decrypt(emsg3, privKey); - if (DataHelper.eq(dmsg3, msg3)) - _log.info("PASSED: Sessions msg 3"); - else { - _log.error("FAILED: Sessions msg 3"); - return; - } - - SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, secondTags); - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - if (curTag == null) { - _log.error("Not able to consume next tag for message 4"); - return; - } - if (curKey == null) { - _log.error("Not able to consume next KEY for message 4"); - return; - } - - byte emsg4[] = ElGamalAESEngine.encrypt(msg4, pubKey, curKey, null, curTag, 64); - byte dmsg4[] = ElGamalAESEngine.decrypt(emsg4, privKey); - if (DataHelper.eq(dmsg4, msg4)) - _log.info("PASSED: Sessions msg 4"); - else { - _log.error("FAILED: Sessions msg 4"); - return; - } - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - if (curTag == null) { - _log.error("Not able to consume next tag for message 5"); - return; - } - if (curKey == null) { - _log.error("Not able to consume next KEY for message 5"); - return; - } - - byte emsg5[] = ElGamalAESEngine.encrypt(msg5, pubKey, curKey, null, curTag, 64); - byte dmsg5[] = ElGamalAESEngine.decrypt(emsg5, privKey); - if (DataHelper.eq(dmsg5, msg5)) - _log.info("PASSED: Sessions msg 5"); - else { - _log.error("FAILED: Sessions msg 5"); - return; - } - } + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + SessionKey curKey = _context.sessionKeyManager().createSession(pubKey); + + SessionTag tag1 = new SessionTag(true); + SessionTag tag2 = new SessionTag(true); + SessionTag tag3 = new SessionTag(true); + SessionTag tag4 = new SessionTag(true); + + HashSet firstTags = new HashSet(); + firstTags.add(tag1); + firstTags.add(tag2); + + HashSet secondTags = new HashSet(); + secondTags.add(tag3); + secondTags.add(tag4); + + byte[] msg1 = "msg 1".getBytes(); + byte[] msg2 = "msg 2".getBytes(); + byte[] msg3 = "msg 3".getBytes(); + byte[] msg4 = "msg 4".getBytes(); + byte[] msg5 = "msg 5".getBytes(); + + byte emsg1[] = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, firstTags, 64); + byte dmsg1[] = _context.elGamalAESEngine().decrypt(emsg1, privKey); + if (DataHelper.eq(dmsg1, msg1)) + _log.info("PASSED: Sessions msg 1"); + else { + _log.error("FAILED: Sessions msg 1"); + return; + } + + _context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags); + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + if (curTag == null) { + _log.error("Not able to consume next tag for message 2"); + return; + } + + byte emsg2[] = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, null, curTag, 64); + byte dmsg2[] = _context.elGamalAESEngine().decrypt(emsg2, privKey); + if (DataHelper.eq(dmsg2, msg2)) + _log.info("PASSED: Sessions msg 2"); + else { + _log.error("FAILED: Sessions msg 2"); + return; + } + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + if (curTag == null) { + _log.error("Not able to consume next tag for message 3"); + return; + } + if (curKey == null) { + _log.error("Not able to consume next KEY for message 3"); + return; + } + + byte emsg3[] = _context.elGamalAESEngine().encrypt(msg3, pubKey, curKey, secondTags, curTag, 64); + byte dmsg3[] = _context.elGamalAESEngine().decrypt(emsg3, privKey); + if (DataHelper.eq(dmsg3, msg3)) + _log.info("PASSED: Sessions msg 3"); + else { + _log.error("FAILED: Sessions msg 3"); + return; + } + + _context.sessionKeyManager().tagsDelivered(pubKey, curKey, secondTags); + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + if (curTag == null) { + _log.error("Not able to consume next tag for message 4"); + return; + } + if (curKey == null) { + _log.error("Not able to consume next KEY for message 4"); + return; + } + + byte emsg4[] = _context.elGamalAESEngine().encrypt(msg4, pubKey, curKey, null, curTag, 64); + byte dmsg4[] = _context.elGamalAESEngine().decrypt(emsg4, privKey); + if (DataHelper.eq(dmsg4, msg4)) + _log.info("PASSED: Sessions msg 4"); + else { + _log.error("FAILED: Sessions msg 4"); + return; + } + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + if (curTag == null) { + _log.error("Not able to consume next tag for message 5"); + return; + } + if (curKey == null) { + _log.error("Not able to consume next KEY for message 5"); + return; + } + + byte emsg5[] = _context.elGamalAESEngine().encrypt(msg5, pubKey, curKey, null, curTag, 64); + byte dmsg5[] = _context.elGamalAESEngine().decrypt(emsg5, privKey); + if (DataHelper.eq(dmsg5, msg5)) + _log.info("PASSED: Sessions msg 5"); + else { + _log.error("FAILED: Sessions msg 5"); + return; + } + } /** - * Run tagsIncluded useTag rekey - * 1 yes (2) no no - * 2 no yes no - * 3 yes (2) yes yes - * 4 no yes no - * 5 no yes no + * Run tagsIncluded useTag rekey + * 1 yes (2) no no + * 2 no yes no + * 3 yes (2) yes yes + * 4 no yes no + * 5 no yes no */ public void testRekeying() throws Exception { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); - SessionKey nextKey = KeyGenerator.getInstance().generateSessionKey(); - - SessionTag tag1 = new SessionTag(true); - SessionTag tag2 = new SessionTag(true); - SessionTag tag3 = new SessionTag(true); - SessionTag tag4 = new SessionTag(true); - - HashSet firstTags = new HashSet(); - firstTags.add(tag1); - firstTags.add(tag2); - - HashSet secondTags = new HashSet(); - secondTags.add(tag3); - secondTags.add(tag4); - - byte[] msg1 = "msg 1".getBytes(); - byte[] msg2 = "msg 2".getBytes(); - byte[] msg3 = "msg 3".getBytes(); - byte[] msg4 = "msg 4".getBytes(); - byte[] msg5 = "msg 5".getBytes(); - - byte emsg1[] = ElGamalAESEngine.encrypt(msg1, pubKey, curKey, firstTags, 64); - byte dmsg1[] = ElGamalAESEngine.decrypt(emsg1, privKey); - if (DataHelper.eq(dmsg1, msg1)) - _log.info("PASSED: Sessions msg 1"); - else { - _log.error("FAILED: Sessions msg 1"); - return; - } - - SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, firstTags); - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - SessionTag curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - if (curTag == null) { - _log.error("Not able to consume next tag for message 2"); - return; - } - - byte emsg2[] = ElGamalAESEngine.encrypt(msg2, pubKey, curKey, null, curTag, 64); - byte dmsg2[] = ElGamalAESEngine.decrypt(emsg2, privKey); - if (DataHelper.eq(dmsg2, msg2)) - _log.info("PASSED: Sessions msg 2"); - else { - _log.error("FAILED: Sessions msg 2"); - return; - } - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - if (curTag == null) { - _log.error("Not able to consume next tag for message 3"); - return; - } - if (curKey == null) { - _log.error("Not able to consume next KEY for message 3"); - return; - } - - byte emsg3[] = ElGamalAESEngine.encrypt(msg3, pubKey, curKey, secondTags, curTag, nextKey, 64); - byte dmsg3[] = ElGamalAESEngine.decrypt(emsg3, privKey); - if (DataHelper.eq(dmsg3, msg3)) - _log.info("PASSED: Sessions msg 3"); - else { - _log.error("FAILED: Sessions msg 3"); - return; - } - - SessionKeyManager.getInstance().tagsDelivered(pubKey, nextKey, secondTags); // note nextKey not curKey - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - if (curTag == null) { - _log.error("Not able to consume next tag for message 4"); - return; - } - if (curKey == null) { - _log.error("Not able to consume next KEY for message 4"); - return; - } - - byte emsg4[] = ElGamalAESEngine.encrypt(msg4, pubKey, curKey, null, curTag, 64); - byte dmsg4[] = ElGamalAESEngine.decrypt(emsg4, privKey); - if (DataHelper.eq(dmsg4, msg4)) - _log.info("PASSED: Sessions msg 4"); - else { - _log.error("FAILED: Sessions msg 4"); - return; - } - - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - if (curTag == null) { - _log.error("Not able to consume next tag for message 5"); - return; - } - if (curKey == null) { - _log.error("Not able to consume next KEY for message 5"); - return; - } - - byte emsg5[] = ElGamalAESEngine.encrypt(msg5, pubKey, curKey, null, curTag, 64); - byte dmsg5[] = ElGamalAESEngine.decrypt(emsg5, privKey); - if (DataHelper.eq(dmsg5, msg5)) - _log.info("PASSED: Sessions msg 5"); - else { - _log.error("FAILED: Sessions msg 5"); - return; - } - } - + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + SessionKey curKey = _context.sessionKeyManager().createSession(pubKey); + SessionKey nextKey = KeyGenerator.getInstance().generateSessionKey(); + + SessionTag tag1 = new SessionTag(true); + SessionTag tag2 = new SessionTag(true); + SessionTag tag3 = new SessionTag(true); + SessionTag tag4 = new SessionTag(true); + + HashSet firstTags = new HashSet(); + firstTags.add(tag1); + firstTags.add(tag2); + + HashSet secondTags = new HashSet(); + secondTags.add(tag3); + secondTags.add(tag4); + + byte[] msg1 = "msg 1".getBytes(); + byte[] msg2 = "msg 2".getBytes(); + byte[] msg3 = "msg 3".getBytes(); + byte[] msg4 = "msg 4".getBytes(); + byte[] msg5 = "msg 5".getBytes(); + + byte emsg1[] = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, firstTags, 64); + byte dmsg1[] = _context.elGamalAESEngine().decrypt(emsg1, privKey); + if (DataHelper.eq(dmsg1, msg1)) + _log.info("PASSED: Sessions msg 1"); + else { + _log.error("FAILED: Sessions msg 1"); + return; + } + + _context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags); + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + if (curTag == null) { + _log.error("Not able to consume next tag for message 2"); + return; + } + + byte emsg2[] = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, null, curTag, 64); + byte dmsg2[] = _context.elGamalAESEngine().decrypt(emsg2, privKey); + if (DataHelper.eq(dmsg2, msg2)) + _log.info("PASSED: Sessions msg 2"); + else { + _log.error("FAILED: Sessions msg 2"); + return; + } + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + if (curTag == null) { + _log.error("Not able to consume next tag for message 3"); + return; + } + if (curKey == null) { + _log.error("Not able to consume next KEY for message 3"); + return; + } + + byte emsg3[] = _context.elGamalAESEngine().encrypt(msg3, pubKey, curKey, secondTags, curTag, nextKey, 64); + byte dmsg3[] = _context.elGamalAESEngine().decrypt(emsg3, privKey); + if (DataHelper.eq(dmsg3, msg3)) + _log.info("PASSED: Sessions msg 3"); + else { + _log.error("FAILED: Sessions msg 3"); + return; + } + + _context.sessionKeyManager().tagsDelivered(pubKey, nextKey, secondTags); // note nextKey not curKey + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + if (curTag == null) { + _log.error("Not able to consume next tag for message 4"); + return; + } + if (curKey == null) { + _log.error("Not able to consume next KEY for message 4"); + return; + } + + byte emsg4[] = _context.elGamalAESEngine().encrypt(msg4, pubKey, curKey, null, curTag, 64); + byte dmsg4[] = _context.elGamalAESEngine().decrypt(emsg4, privKey); + if (DataHelper.eq(dmsg4, msg4)) + _log.info("PASSED: Sessions msg 4"); + else { + _log.error("FAILED: Sessions msg 4"); + return; + } + + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + if (curTag == null) { + _log.error("Not able to consume next tag for message 5"); + return; + } + if (curKey == null) { + _log.error("Not able to consume next KEY for message 5"); + return; + } + + byte emsg5[] = _context.elGamalAESEngine().encrypt(msg5, pubKey, curKey, null, curTag, 64); + byte dmsg5[] = _context.elGamalAESEngine().decrypt(emsg5, privKey); + if (DataHelper.eq(dmsg5, msg5)) + _log.info("PASSED: Sessions msg 5"); + else { + _log.error("FAILED: Sessions msg 5"); + return; + } + } + /** - * 20 tags every 10 messages, rekey every 50 + * 20 tags every 10 messages, rekey every 50 */ public void testLongSession() throws Exception { - int num = 1000; - long start = Clock.getInstance().now(); - testLongSession(num); - long end = Clock.getInstance().now(); - long time = end - start; - float msEach = (float)num / time; - _log.error("Test long session duration: " + num + " messages in " + time + "ms (or " + msEach + "ms each)"); + int num = 1000; + long start = Clock.getInstance().now(); + testLongSession(num); + long end = Clock.getInstance().now(); + long time = end - start; + float msEach = (float)num / time; + _log.error("Test long session duration: " + num + " messages in " + time + "ms (or " + msEach + "ms each)"); } public void testLongSession(int numMsgs) throws Exception { - Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); - PublicKey pubKey = (PublicKey)keys[0]; - PrivateKey privKey = (PrivateKey)keys[1]; - SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); - - for (int i = 0; i < numMsgs; i++) { - Set tags = null; - SessionKey nextKey = null; - curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); - SessionTag curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); - - int availTags = SessionKeyManager.getInstance().getAvailableTags(pubKey, curKey); - if ((availTags < 1)) { - tags = generateNewTags(50); - _log.info("Generating new tags"); - } else { - _log.info("Tags already available: " + availTags + " curTag: " + curTag); - } - if (i % 50 == 0) - nextKey = KeyGenerator.getInstance().generateSessionKey(); - - byte[] msg = ("msg " + i).getBytes(); - - byte emsg[] = ElGamalAESEngine.encrypt(msg, pubKey, curKey, tags, curTag, nextKey, 64); - byte dmsg[] = ElGamalAESEngine.decrypt(emsg, privKey); - if (DataHelper.eq(dmsg, msg)) - _log.info("PASSED: Long session msg " + i); - else { - _log.error("FAILED: Long session msg " + i); - return; - } - - if ( (tags != null) && (tags.size() > 0) ) { - if (nextKey == null) { - SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, tags); - } else { - SessionKeyManager.getInstance().tagsDelivered(pubKey, nextKey, tags); - } - } - } + Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); + PublicKey pubKey = (PublicKey)keys[0]; + PrivateKey privKey = (PrivateKey)keys[1]; + SessionKey curKey = _context.sessionKeyManager().createSession(pubKey); + + for (int i = 0; i < numMsgs; i++) { + Set tags = null; + SessionKey nextKey = null; + curKey = _context.sessionKeyManager().getCurrentKey(pubKey); + SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey); + + int availTags = _context.sessionKeyManager().getAvailableTags(pubKey, curKey); + if ((availTags < 1)) { + tags = generateNewTags(50); + _log.info("Generating new tags"); + } else { + _log.info("Tags already available: " + availTags + " curTag: " + curTag); + } + if (i % 50 == 0) + nextKey = KeyGenerator.getInstance().generateSessionKey(); + + byte[] msg = ("msg " + i).getBytes(); + + byte emsg[] = _context.elGamalAESEngine().encrypt(msg, pubKey, curKey, tags, curTag, nextKey, 64); + byte dmsg[] = _context.elGamalAESEngine().decrypt(emsg, privKey); + if (DataHelper.eq(dmsg, msg)) + _log.info("PASSED: Long session msg " + i); + else { + _log.error("FAILED: Long session msg " + i); + return; + } + + if ( (tags != null) && (tags.size() > 0) ) { + if (nextKey == null) { + _context.sessionKeyManager().tagsDelivered(pubKey, curKey, tags); + } else { + _context.sessionKeyManager().tagsDelivered(pubKey, nextKey, tags); + } + } + } } - + private Set generateNewTags(int numTags) { - Set tags = new HashSet(numTags); - for (int i = 0; i < numTags; i++) - tags.add(new SessionTag(true)); - return tags; + Set tags = new HashSet(numTags); + for (int i = 0; i < numTags; i++) + tags.add(new SessionTag(true)); + return tags; } } diff --git a/core/java/test/net/i2p/data/StructureTest.java b/core/java/test/net/i2p/data/StructureTest.java index 35b9c737e..2a511d5ae 100644 --- a/core/java/test/net/i2p/data/StructureTest.java +++ b/core/java/test/net/i2p/data/StructureTest.java @@ -15,6 +15,7 @@ import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataStructure; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Utility class for wrapping data structure tests @@ -23,6 +24,7 @@ import net.i2p.util.Log; */ public abstract class StructureTest implements TestDataGenerator, TestDataPrinter { private static final Log _log = new Log(StructureTest.class); + protected static I2PAppContext _context = I2PAppContext.getGlobalContext(); public abstract DataStructure createDataStructure() throws DataFormatException; public abstract DataStructure createStructureToRead(); diff --git a/router/java/src/net/i2p/data/i2np/DataMessage.java b/router/java/src/net/i2p/data/i2np/DataMessage.java index c7d19c869..be18d3c7a 100644 --- a/router/java/src/net/i2p/data/i2np/DataMessage.java +++ b/router/java/src/net/i2p/data/i2np/DataMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -15,6 +15,7 @@ import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines a message containing arbitrary bytes of data @@ -26,8 +27,9 @@ public class DataMessage extends I2NPMessageImpl { public final static int MESSAGE_TYPE = 20; private byte _data[]; - public DataMessage() { - _data = null; + public DataMessage(I2PAppContext context) { + super(context); + _data = null; } public byte[] getData() { return _data; } @@ -36,23 +38,23 @@ public class DataMessage extends I2NPMessageImpl { public int getSize() { return _data.length; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - int size = (int)DataHelper.readLong(in, 4); - _data = new byte[size]; - int read = read(in, _data); - if (read != size) - throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")"); + int size = (int)DataHelper.readLong(in, 4); + _data = new byte[size]; + int read = read(in, _data); + if (read != size) + throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")"); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - ByteArrayOutputStream os = new ByteArrayOutputStream((_data != null ? _data.length + 4 : 4)); + ByteArrayOutputStream os = new ByteArrayOutputStream((_data != null ? _data.length + 4 : 4)); try { - DataHelper.writeLong(os, 4, (_data != null ? _data.length : 0)); - os.write(_data); + DataHelper.writeLong(os, 4, (_data != null ? _data.length : 0)); + os.write(_data); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -62,7 +64,7 @@ public class DataMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(getData()); + return DataHelper.hashCode(getData()); } public boolean equals(Object object) { @@ -74,7 +76,7 @@ public class DataMessage extends I2NPMessageImpl { } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[DataMessage: "); buf.append("\n\tData: ").append(DataHelper.toString(getData(), 64)); diff --git a/router/java/src/net/i2p/data/i2np/DatabaseFindNearestMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseFindNearestMessage.java deleted file mode 100644 index f3078734b..000000000 --- a/router/java/src/net/i2p/data/i2np/DatabaseFindNearestMessage.java +++ /dev/null @@ -1,99 +0,0 @@ -package net.i2p.data.i2np; -/* - * 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.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import net.i2p.data.DataFormatException; -import net.i2p.data.DataHelper; -import net.i2p.data.Hash; -import net.i2p.util.Log; - -/** - * Defines the message a router sends to another router to help integrate into - * the network by searching for routers in a particular keyspace. - * - * @author jrandom - */ -public class DatabaseFindNearestMessage extends I2NPMessageImpl { - private final static Log _log = new Log(DatabaseFindNearestMessage.class); - public final static int MESSAGE_TYPE = 4; - private Hash _key; - private Hash _from; - - public DatabaseFindNearestMessage() { - setSearchKey(null); - setFromHash(null); - } - - /** - * Defines the key being searched for - */ - public Hash getSearchKey() { return _key; } - public void setSearchKey(Hash key) { _key = key; } - - /** - * Contains the SHA256 Hash of the RouterIdentity sending the message - */ - public Hash getFromHash() { return _from; } - public void setFromHash(Hash from) { _from = from; } - - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _key = new Hash(); - _key.readBytes(in); - _from = new Hash(); - _from.readBytes(in); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); - } - } - - protected byte[] writeMessage() throws I2NPMessageException, IOException { - if ( (_key == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out"); - - ByteArrayOutputStream os = new ByteArrayOutputStream(32); - try { - _key.writeBytes(os); - _from.writeBytes(os); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Error writing out the message data", dfe); - } - return os.toByteArray(); - } - - public int getType() { return MESSAGE_TYPE; } - - public int hashCode() { - return DataHelper.hashCode(getSearchKey()) + - DataHelper.hashCode(getFromHash()); - } - - public boolean equals(Object object) { - if ( (object != null) && (object instanceof DatabaseFindNearestMessage) ) { - DatabaseFindNearestMessage msg = (DatabaseFindNearestMessage)object; - return DataHelper.eq(getSearchKey(),msg.getSearchKey()) && - DataHelper.eq(getFromHash(),msg.getFromHash()); - } else { - return false; - } - } - - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append("[DatabaseFindNearestMessage: "); - buf.append("\n\tSearch Key: ").append(getSearchKey()); - buf.append("\n\tFrom: ").append(getFromHash()); - buf.append("]"); - return buf.toString(); - } -} diff --git a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java index 8ee73bbba..7d7533fc1 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -21,6 +21,7 @@ import net.i2p.data.Hash; import net.i2p.data.RouterInfo; import net.i2p.data.TunnelId; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines the message a router sends to another router to search for a @@ -36,10 +37,11 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { private TunnelId _replyTunnel; private Set _dontIncludePeers; - public DatabaseLookupMessage() { - setSearchKey(null); - setFrom(null); - setDontIncludePeers(null); + public DatabaseLookupMessage(I2PAppContext context) { + super(context); + setSearchKey(null); + setFrom(null); + setDontIncludePeers(null); } /** @@ -68,63 +70,63 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { * @return Set of Hash objects, each of which is the H(routerIdentity) to skip */ public Set getDontIncludePeers() { return _dontIncludePeers; } - public void setDontIncludePeers(Set peers) { - if (peers != null) - _dontIncludePeers = new HashSet(peers); - else - _dontIncludePeers = null; + public void setDontIncludePeers(Set peers) { + if (peers != null) + _dontIncludePeers = new HashSet(peers); + else + _dontIncludePeers = null; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _key = new Hash(); - _key.readBytes(in); - _from = new RouterInfo(); - _from.readBytes(in); - boolean tunnelSpecified = DataHelper.readBoolean(in).booleanValue(); - if (tunnelSpecified) { - _replyTunnel = new TunnelId(); - _replyTunnel.readBytes(in); - } - int numPeers = (int)DataHelper.readLong(in, 2); - if ( (numPeers < 0) || (numPeers >= (1<<16) ) ) - throw new DataFormatException("Invalid number of peers - " + numPeers); - Set peers = new HashSet(numPeers); - for (int i = 0; i < numPeers; i++) { - Hash peer = new Hash(); - peer.readBytes(in); - peers.add(peer); - } - _dontIncludePeers = peers; + _key = new Hash(); + _key.readBytes(in); + _from = new RouterInfo(); + _from.readBytes(in); + boolean tunnelSpecified = DataHelper.readBoolean(in).booleanValue(); + if (tunnelSpecified) { + _replyTunnel = new TunnelId(); + _replyTunnel.readBytes(in); + } + int numPeers = (int)DataHelper.readLong(in, 2); + if ( (numPeers < 0) || (numPeers >= (1<<16) ) ) + throw new DataFormatException("Invalid number of peers - " + numPeers); + Set peers = new HashSet(numPeers); + for (int i = 0; i < numPeers; i++) { + Hash peer = new Hash(); + peer.readBytes(in); + peers.add(peer); + } + _dontIncludePeers = peers; } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if (_key == null) throw new I2NPMessageException("Key being searched for not specified"); - if (_from == null) throw new I2NPMessageException("From address not specified"); - + if (_key == null) throw new I2NPMessageException("Key being searched for not specified"); + if (_from == null) throw new I2NPMessageException("From address not specified"); + ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - _key.writeBytes(os); - _from.writeBytes(os); - if (_replyTunnel != null) { - DataHelper.writeBoolean(os, Boolean.TRUE); - _replyTunnel.writeBytes(os); - } else { - DataHelper.writeBoolean(os, Boolean.FALSE); - } - if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) { - DataHelper.writeLong(os, 2, 0); - } else { - DataHelper.writeLong(os, 2, _dontIncludePeers.size()); - for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) { - Hash peer = (Hash)iter.next(); - peer.writeBytes(os); - } - } + _key.writeBytes(os); + _from.writeBytes(os); + if (_replyTunnel != null) { + DataHelper.writeBoolean(os, Boolean.TRUE); + _replyTunnel.writeBytes(os); + } else { + DataHelper.writeBoolean(os, Boolean.FALSE); + } + if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) { + DataHelper.writeLong(os, 2, 0); + } else { + DataHelper.writeLong(os, 2, _dontIncludePeers.size()); + for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) { + Hash peer = (Hash)iter.next(); + peer.writeBytes(os); + } + } } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -134,25 +136,25 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(getSearchKey()) + - DataHelper.hashCode(getFrom()) + - DataHelper.hashCode(getReplyTunnel()) + - DataHelper.hashCode(_dontIncludePeers); + return DataHelper.hashCode(getSearchKey()) + + DataHelper.hashCode(getFrom()) + + DataHelper.hashCode(getReplyTunnel()) + + DataHelper.hashCode(_dontIncludePeers); } public boolean equals(Object object) { if ( (object != null) && (object instanceof DatabaseLookupMessage) ) { DatabaseLookupMessage msg = (DatabaseLookupMessage)object; return DataHelper.eq(getSearchKey(),msg.getSearchKey()) && - DataHelper.eq(getFrom(),msg.getFrom()) && - DataHelper.eq(getReplyTunnel(),msg.getReplyTunnel()) && - DataHelper.eq(_dontIncludePeers,msg.getDontIncludePeers()); + DataHelper.eq(getFrom(),msg.getFrom()) && + DataHelper.eq(getReplyTunnel(),msg.getReplyTunnel()) && + DataHelper.eq(_dontIncludePeers,msg.getDontIncludePeers()); } else { return false; } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[DatabaseLookupMessage: "); buf.append("\n\tSearch Key: ").append(getSearchKey()); diff --git a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java index 0bd5abbd5..ea996c7a8 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -21,10 +21,11 @@ import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.RouterInfo; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** - * Defines the message a router sends to another router in response to a - * search (DatabaseFindNearest or DatabaseLookup) when it doesn't have the value, + * Defines the message a router sends to another router in response to a + * search (DatabaseFindNearest or DatabaseLookup) when it doesn't have the value, * specifying what routers it would search. * * @author jrandom @@ -36,10 +37,11 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { private List _routerInfoStructures; private Hash _from; - public DatabaseSearchReplyMessage() { - setSearchKey(null); - _routerInfoStructures = new ArrayList(); - setFromHash(null); + public DatabaseSearchReplyMessage(I2PAppContext context) { + super(context); + setSearchKey(null); + _routerInfoStructures = new ArrayList(); + setFromHash(null); } /** @@ -57,58 +59,58 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { public void setFromHash(Hash from) { _from = from; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _key = new Hash(); - _key.readBytes(in); - - int compressedLength = (int)DataHelper.readLong(in, 2); - byte compressedData[] = new byte[compressedLength]; - int read = DataHelper.read(in, compressedData); - if (read != compressedLength) - throw new IOException("Not enough data to decompress"); - byte decompressedData[] = DataHelper.decompress(compressedData); - ByteArrayInputStream bais = new ByteArrayInputStream(decompressedData); - int num = (int)DataHelper.readLong(bais, 1); - _routerInfoStructures.clear(); - for (int i = 0; i < num; i++) { - RouterInfo info = new RouterInfo(); - info.readBytes(bais); - addReply(info); - } - - _from = new Hash(); - _from.readBytes(in); + _key = new Hash(); + _key.readBytes(in); + + int compressedLength = (int)DataHelper.readLong(in, 2); + byte compressedData[] = new byte[compressedLength]; + int read = DataHelper.read(in, compressedData); + if (read != compressedLength) + throw new IOException("Not enough data to decompress"); + byte decompressedData[] = DataHelper.decompress(compressedData); + ByteArrayInputStream bais = new ByteArrayInputStream(decompressedData); + int num = (int)DataHelper.readLong(bais, 1); + _routerInfoStructures.clear(); + for (int i = 0; i < num; i++) { + RouterInfo info = new RouterInfo(); + info.readBytes(bais); + addReply(info); + } + + _from = new Hash(); + _from.readBytes(in); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if (_key == null) - throw new I2NPMessageException("Key in reply to not specified"); - if (_routerInfoStructures == null) - throw new I2NPMessageException("RouterInfo replies are null"); - if (_routerInfoStructures.size() <= 0) - throw new I2NPMessageException("No replies specified in SearchReply! Always include oneself!"); - if (_from == null) - throw new I2NPMessageException("No 'from' address specified!"); - + if (_key == null) + throw new I2NPMessageException("Key in reply to not specified"); + if (_routerInfoStructures == null) + throw new I2NPMessageException("RouterInfo replies are null"); + if (_routerInfoStructures.size() <= 0) + throw new I2NPMessageException("No replies specified in SearchReply! Always include oneself!"); + if (_from == null) + throw new I2NPMessageException("No 'from' address specified!"); + ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - _key.writeBytes(os); - - ByteArrayOutputStream baos = new ByteArrayOutputStream(512); - DataHelper.writeLong(baos, 1, _routerInfoStructures.size()); - for (int i = 0; i < getNumReplies(); i++) { - RouterInfo info = getReply(i); - info.writeBytes(baos); - } - - byte compressed[] = DataHelper.compress(baos.toByteArray()); - DataHelper.writeLong(os, 2, compressed.length); - os.write(compressed); - _from.writeBytes(os); + _key.writeBytes(os); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(512); + DataHelper.writeLong(baos, 1, _routerInfoStructures.size()); + for (int i = 0; i < getNumReplies(); i++) { + RouterInfo info = getReply(i); + info.writeBytes(baos); + } + + byte compressed[] = DataHelper.compress(baos.toByteArray()); + DataHelper.writeLong(os, 2, compressed.length); + os.write(compressed); + _from.writeBytes(os); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -121,27 +123,27 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { if ( (object != null) && (object instanceof DatabaseSearchReplyMessage) ) { DatabaseSearchReplyMessage msg = (DatabaseSearchReplyMessage)object; return DataHelper.eq(getSearchKey(),msg.getSearchKey()) && - DataHelper.eq(getFromHash(),msg.getFromHash()) && - DataHelper.eq(_routerInfoStructures,msg._routerInfoStructures); + DataHelper.eq(getFromHash(),msg.getFromHash()) && + DataHelper.eq(_routerInfoStructures,msg._routerInfoStructures); } else { return false; } } public int hashCode() { - return DataHelper.hashCode(getSearchKey()) + - DataHelper.hashCode(getFromHash()) + - DataHelper.hashCode(_routerInfoStructures); + return DataHelper.hashCode(getSearchKey()) + + DataHelper.hashCode(getFromHash()) + + DataHelper.hashCode(_routerInfoStructures); } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[DatabaseSearchReplyMessage: "); buf.append("\n\tSearch Key: ").append(getSearchKey()); buf.append("\n\tReplies: # = ").append(getNumReplies()); - for (int i = 0; i < getNumReplies(); i++) { - buf.append("\n\t\tReply [").append(i).append("]: ").append(getReply(i)); - } + for (int i = 0; i < getNumReplies(); i++) { + buf.append("\n\t\tReply [").append(i).append("]: ").append(getReply(i)); + } buf.append("\n\tFrom: ").append(getFromHash()); buf.append("]"); return buf.toString(); diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index 0221e2f4a..223c33d20 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -19,9 +19,10 @@ import net.i2p.data.Hash; import net.i2p.data.LeaseSet; import net.i2p.data.RouterInfo; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** - * Defines the message a router sends to another router to test the network + * Defines the message a router sends to another router to test the network * database reachability, as well as the reply message sent back. * * @author jrandom @@ -37,11 +38,12 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { public final static int KEY_TYPE_ROUTERINFO = 0; public final static int KEY_TYPE_LEASESET = 1; - public DatabaseStoreMessage() { - setValueType(-1); - setKey(null); - setLeaseSet(null); - setRouterInfo(null); + public DatabaseStoreMessage(I2PAppContext context) { + super(context); + setValueType(-1); + setKey(null); + setLeaseSet(null); + setRouterInfo(null); } /** @@ -56,10 +58,10 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { * */ public RouterInfo getRouterInfo() { return _info; } - public void setRouterInfo(RouterInfo routerInfo) { - _info = routerInfo; - if (_info != null) - setValueType(KEY_TYPE_ROUTERINFO); + public void setRouterInfo(RouterInfo routerInfo) { + _info = routerInfo; + if (_info != null) + setValueType(KEY_TYPE_ROUTERINFO); } /** @@ -67,14 +69,14 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { * */ public LeaseSet getLeaseSet() { return _leaseSet; } - public void setLeaseSet(LeaseSet leaseSet) { - _leaseSet = leaseSet; - if (_leaseSet != null) - setValueType(KEY_TYPE_LEASESET); + public void setLeaseSet(LeaseSet leaseSet) { + _leaseSet = leaseSet; + if (_leaseSet != null) + setValueType(KEY_TYPE_LEASESET); } /** - * Defines type of key being stored in the network database - + * Defines type of key being stored in the network database - * either KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET * */ @@ -82,52 +84,52 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { public void setValueType(int type) { _type = type; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _key = new Hash(); - _key.readBytes(in); - _log.debug("Hash read: " + _key.toBase64()); - _type = (int)DataHelper.readLong(in, 1); - if (_type == KEY_TYPE_LEASESET) { - _leaseSet = new LeaseSet(); - _leaseSet.readBytes(in); - } else if (_type == KEY_TYPE_ROUTERINFO) { - _info = new RouterInfo(); - int compressedSize = (int)DataHelper.readLong(in, 2); - byte compressed[] = new byte[compressedSize]; - int read = DataHelper.read(in, compressed); - if (read != compressedSize) - throw new I2NPMessageException("Invalid compressed data size"); - ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed)); - _info.readBytes(bais); - } else { - throw new I2NPMessageException("Invalid type of key read from the structure - " + _type); - } + _key = new Hash(); + _key.readBytes(in); + _log.debug("Hash read: " + _key.toBase64()); + _type = (int)DataHelper.readLong(in, 1); + if (_type == KEY_TYPE_LEASESET) { + _leaseSet = new LeaseSet(); + _leaseSet.readBytes(in); + } else if (_type == KEY_TYPE_ROUTERINFO) { + _info = new RouterInfo(); + int compressedSize = (int)DataHelper.readLong(in, 2); + byte compressed[] = new byte[compressedSize]; + int read = DataHelper.read(in, compressed); + if (read != compressedSize) + throw new I2NPMessageException("Invalid compressed data size"); + ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed)); + _info.readBytes(bais); + } else { + throw new I2NPMessageException("Invalid type of key read from the structure - " + _type); + } } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if (_key == null) throw new I2NPMessageException("Invalid key"); - if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type"); - if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set"); - if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info"); - + if (_key == null) throw new I2NPMessageException("Invalid key"); + if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type"); + if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set"); + if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info"); + ByteArrayOutputStream os = new ByteArrayOutputStream(256); try { - _key.writeBytes(os); - DataHelper.writeLong(os, 1, _type); - if (_type == KEY_TYPE_LEASESET) { - _leaseSet.writeBytes(os); - } else if (_type == KEY_TYPE_ROUTERINFO) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024); - _info.writeBytes(baos); - byte uncompressed[] = baos.toByteArray(); - byte compressed[] = DataHelper.compress(uncompressed); - DataHelper.writeLong(os, 2, compressed.length); - os.write(compressed); - } + _key.writeBytes(os); + DataHelper.writeLong(os, 1, _type); + if (_type == KEY_TYPE_LEASESET) { + _leaseSet.writeBytes(os); + } else if (_type == KEY_TYPE_ROUTERINFO) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024); + _info.writeBytes(baos); + byte uncompressed[] = baos.toByteArray(); + byte compressed[] = DataHelper.compress(uncompressed); + DataHelper.writeLong(os, 2, compressed.length); + os.write(compressed); + } } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -137,29 +139,29 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(getKey()) + - DataHelper.hashCode(getLeaseSet()) + - DataHelper.hashCode(getRouterInfo()) + - getValueType(); + return DataHelper.hashCode(getKey()) + + DataHelper.hashCode(getLeaseSet()) + + DataHelper.hashCode(getRouterInfo()) + + getValueType(); } public boolean equals(Object object) { if ( (object != null) && (object instanceof DatabaseStoreMessage) ) { DatabaseStoreMessage msg = (DatabaseStoreMessage)object; return DataHelper.eq(getKey(),msg.getKey()) && - DataHelper.eq(getLeaseSet(),msg.getLeaseSet()) && - DataHelper.eq(getRouterInfo(),msg.getRouterInfo()) && - DataHelper.eq(getValueType(),msg.getValueType()); + DataHelper.eq(getLeaseSet(),msg.getLeaseSet()) && + DataHelper.eq(getRouterInfo(),msg.getRouterInfo()) && + DataHelper.eq(getValueType(),msg.getValueType()); } else { return false; } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[DatabaseStoreMessage: "); - buf.append("\n\tExpiration: ").append(getMessageExpiration()); - buf.append("\n\tUnique ID: ").append(getUniqueId()); + buf.append("\n\tExpiration: ").append(getMessageExpiration()); + buf.append("\n\tUnique ID: ").append(getUniqueId()); buf.append("\n\tKey: ").append(getKey()); buf.append("\n\tValue Type: ").append(getValueType()); buf.append("\n\tRouter Info: ").append(getRouterInfo()); diff --git a/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java b/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java index 18c7d564e..0d4569917 100644 --- a/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java +++ b/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -16,6 +16,7 @@ import java.util.Date; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines the message sent back in reply to a message when requested, containing @@ -29,9 +30,10 @@ public class DeliveryStatusMessage extends I2NPMessageImpl { private long _id; private Date _arrival; - public DeliveryStatusMessage() { - setMessageId(-1); - setArrival(null); + public DeliveryStatusMessage(I2PAppContext context) { + super(context); + setMessageId(-1); + setArrival(null); } public long getMessageId() { return _id; } @@ -41,22 +43,22 @@ public class DeliveryStatusMessage extends I2NPMessageImpl { public void setArrival(Date arrival) { _arrival = arrival; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _id = DataHelper.readLong(in, 4); - _arrival = DataHelper.readDate(in); + _id = DataHelper.readLong(in, 4); + _arrival = DataHelper.readDate(in); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if ( (_id < 0) || (_arrival == null) ) throw new I2NPMessageException("Not enough data to write out"); - + if ( (_id < 0) || (_arrival == null) ) throw new I2NPMessageException("Not enough data to write out"); + ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - DataHelper.writeLong(os, 4, _id); - DataHelper.writeDate(os, _arrival); + DataHelper.writeLong(os, 4, _id); + DataHelper.writeDate(os, _arrival); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -66,21 +68,21 @@ public class DeliveryStatusMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return (int)getMessageId() + - DataHelper.hashCode(getArrival()); + return (int)getMessageId() + + DataHelper.hashCode(getArrival()); } public boolean equals(Object object) { if ( (object != null) && (object instanceof DeliveryStatusMessage) ) { DeliveryStatusMessage msg = (DeliveryStatusMessage)object; return DataHelper.eq(getMessageId(),msg.getMessageId()) && - DataHelper.eq(getArrival(),msg.getArrival()); + DataHelper.eq(getArrival(),msg.getArrival()); } else { return false; } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[DeliveryStatusMessage: "); buf.append("\n\tMessage ID: ").append(getMessageId()); diff --git a/router/java/src/net/i2p/data/i2np/GarlicClove.java b/router/java/src/net/i2p/data/i2np/GarlicClove.java index aec216751..983f09442 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicClove.java +++ b/router/java/src/net/i2p/data/i2np/GarlicClove.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -18,6 +18,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.DataStructureImpl; import net.i2p.util.Log; +import net.i2p.router.RouterContext; /** * Contains one deliverable message encrypted to a router along with instructions @@ -26,7 +27,8 @@ import net.i2p.util.Log; * @author jrandom */ public class GarlicClove extends DataStructureImpl { - private final static Log _log = new Log(GarlicClove.class); + private Log _log; + private RouterContext _context; private DeliveryInstructions _instructions; private I2NPMessage _msg; private long _cloveId; @@ -34,30 +36,34 @@ public class GarlicClove extends DataStructureImpl { private Certificate _certificate; private int _replyAction; private SourceRouteBlock _sourceRouteBlock; + private I2NPMessageHandler _handler; /** No action requested with the source route block */ public final static int ACTION_NONE = 0; - /** - * A DeliveryStatusMessage is requested with the source route block using + /** + * A DeliveryStatusMessage is requested with the source route block using * the cloveId as the id received * */ public final static int ACTION_STATUS = 1; - /** + /** * No DeliveryStatusMessage is requested, but the source route block is * included for message specific replies * */ public final static int ACTION_MESSAGE_SPECIFIC = 2; - public GarlicClove() { - setInstructions(null); - setData(null); - setCloveId(-1); - setExpiration(null); - setCertificate(null); - setSourceRouteBlockAction(ACTION_NONE); - setSourceRouteBlock(null); + public GarlicClove(RouterContext context) { + _context = context; + _log = context.logManager().getLog(GarlicClove.class); + _handler = new I2NPMessageHandler(context); + setInstructions(null); + setData(null); + setCloveId(-1); + setExpiration(null); + setCertificate(null); + setSourceRouteBlockAction(ACTION_NONE); + setSourceRouteBlock(null); } public DeliveryInstructions getInstructions() { return _instructions; } @@ -76,94 +82,94 @@ public class GarlicClove extends DataStructureImpl { public void setSourceRouteBlock(SourceRouteBlock block) { _sourceRouteBlock = block; } public void readBytes(InputStream in) throws DataFormatException, IOException { - _instructions = new DeliveryInstructions(); - _instructions.readBytes(in); - _log.debug("Read instructions: " + _instructions); - try { - _msg = new I2NPMessageHandler().readMessage(in); - } catch (I2NPMessageException ime) { - throw new DataFormatException("Unable to read the message from a garlic clove", ime); - } - _cloveId = DataHelper.readLong(in, 4); - _expiration = DataHelper.readDate(in); - _log.debug("CloveID read: " + _cloveId + " expiration read: " + _expiration); - _certificate = new Certificate(); - _certificate.readBytes(in); - _log.debug("Read cert: " + _certificate); - int replyStyle = (int)DataHelper.readLong(in, 1); - setSourceRouteBlockAction(replyStyle); - if (replyStyle != ACTION_NONE) { - _sourceRouteBlock = new SourceRouteBlock(); - _sourceRouteBlock.readBytes(in); - } + _instructions = new DeliveryInstructions(); + _instructions.readBytes(in); + _log.debug("Read instructions: " + _instructions); + try { + _msg = _handler.readMessage(in); + } catch (I2NPMessageException ime) { + throw new DataFormatException("Unable to read the message from a garlic clove", ime); + } + _cloveId = DataHelper.readLong(in, 4); + _expiration = DataHelper.readDate(in); + _log.debug("CloveID read: " + _cloveId + " expiration read: " + _expiration); + _certificate = new Certificate(); + _certificate.readBytes(in); + _log.debug("Read cert: " + _certificate); + int replyStyle = (int)DataHelper.readLong(in, 1); + setSourceRouteBlockAction(replyStyle); + if (replyStyle != ACTION_NONE) { + _sourceRouteBlock = new SourceRouteBlock(); + _sourceRouteBlock.readBytes(in); + } } public void writeBytes(OutputStream out) throws DataFormatException, IOException { - StringBuffer error = new StringBuffer(); - if (_instructions == null) - error.append("No instructions "); - if (_msg == null) - error.append("No message "); - if (_cloveId < 0) - error.append("CloveID < 0 [").append(_cloveId).append("] "); - if (_expiration == null) - error.append("Expiration is null "); - if (_certificate == null) - error.append("Certificate is null "); - if (_replyAction < 0) - error.append("Reply action is < 0 [").append(_replyAction).append("] ");; - if (error.length() > 0) - throw new DataFormatException(error.toString()); - if ( (_replyAction != 0) && (_sourceRouteBlock == null) ) - throw new DataFormatException("Source route block must be specified for non-null action"); - _instructions.writeBytes(out); - - _log.debug("Wrote instructions: " + _instructions); - _msg.writeBytes(out); - DataHelper.writeLong(out, 4, _cloveId); - DataHelper.writeDate(out, _expiration); - _log.debug("CloveID written: " + _cloveId + " expiration written: " + _expiration); - _certificate.writeBytes(out); - _log.debug("Written cert: " + _certificate); - DataHelper.writeLong(out, 1, _replyAction); - if ( (_replyAction != 0) && (_sourceRouteBlock != null) ) - _sourceRouteBlock.writeBytes(out); + StringBuffer error = new StringBuffer(); + if (_instructions == null) + error.append("No instructions "); + if (_msg == null) + error.append("No message "); + if (_cloveId < 0) + error.append("CloveID < 0 [").append(_cloveId).append("] "); + if (_expiration == null) + error.append("Expiration is null "); + if (_certificate == null) + error.append("Certificate is null "); + if (_replyAction < 0) + error.append("Reply action is < 0 [").append(_replyAction).append("] ");; + if (error.length() > 0) + throw new DataFormatException(error.toString()); + if ( (_replyAction != 0) && (_sourceRouteBlock == null) ) + throw new DataFormatException("Source route block must be specified for non-null action"); + _instructions.writeBytes(out); + + _log.debug("Wrote instructions: " + _instructions); + _msg.writeBytes(out); + DataHelper.writeLong(out, 4, _cloveId); + DataHelper.writeDate(out, _expiration); + _log.debug("CloveID written: " + _cloveId + " expiration written: " + _expiration); + _certificate.writeBytes(out); + _log.debug("Written cert: " + _certificate); + DataHelper.writeLong(out, 1, _replyAction); + if ( (_replyAction != 0) && (_sourceRouteBlock != null) ) + _sourceRouteBlock.writeBytes(out); } public boolean equals(Object obj) { if ( (obj == null) || !(obj instanceof GarlicClove)) return false; - GarlicClove clove = (GarlicClove)obj; - return DataHelper.eq(getCertificate(), clove.getCertificate()) && - DataHelper.eq(getCloveId(), clove.getCloveId()) && - DataHelper.eq(getData(), clove.getData()) && - DataHelper.eq(getExpiration(), clove.getExpiration()) && - DataHelper.eq(getInstructions(), clove.getInstructions()) && - DataHelper.eq(getSourceRouteBlock(), clove.getSourceRouteBlock()) && - (getSourceRouteBlockAction() == clove.getSourceRouteBlockAction()); + GarlicClove clove = (GarlicClove)obj; + return DataHelper.eq(getCertificate(), clove.getCertificate()) && + DataHelper.eq(getCloveId(), clove.getCloveId()) && + DataHelper.eq(getData(), clove.getData()) && + DataHelper.eq(getExpiration(), clove.getExpiration()) && + DataHelper.eq(getInstructions(), clove.getInstructions()) && + DataHelper.eq(getSourceRouteBlock(), clove.getSourceRouteBlock()) && + (getSourceRouteBlockAction() == clove.getSourceRouteBlockAction()); } public int hashCode() { - return DataHelper.hashCode(getCertificate()) + - (int)getCloveId() + - DataHelper.hashCode(getData()) + - DataHelper.hashCode(getExpiration()) + - DataHelper.hashCode(getInstructions()) + - DataHelper.hashCode(getSourceRouteBlock()) + - getSourceRouteBlockAction(); + return DataHelper.hashCode(getCertificate()) + + (int)getCloveId() + + DataHelper.hashCode(getData()) + + DataHelper.hashCode(getExpiration()) + + DataHelper.hashCode(getInstructions()) + + DataHelper.hashCode(getSourceRouteBlock()) + + getSourceRouteBlockAction(); } public String toString() { - StringBuffer buf = new StringBuffer(128); + StringBuffer buf = new StringBuffer(128); buf.append("[GarlicClove: "); - buf.append("\n\tInstructions: ").append(getInstructions()); - buf.append("\n\tCertificate: ").append(getCertificate()); - buf.append("\n\tClove ID: ").append(getCloveId()); - buf.append("\n\tExpiration: ").append(getExpiration()); - buf.append("\n\tSource route style: ").append(getSourceRouteBlockAction()); - buf.append("\n\tSource route block: ").append(getSourceRouteBlock()); - buf.append("\n\tData: ").append(getData()); - buf.append("]"); - return buf.toString(); + buf.append("\n\tInstructions: ").append(getInstructions()); + buf.append("\n\tCertificate: ").append(getCertificate()); + buf.append("\n\tClove ID: ").append(getCloveId()); + buf.append("\n\tExpiration: ").append(getExpiration()); + buf.append("\n\tSource route style: ").append(getSourceRouteBlockAction()); + buf.append("\n\tSource route block: ").append(getSourceRouteBlock()); + buf.append("\n\tData: ").append(getData()); + buf.append("]"); + return buf.toString(); } } diff --git a/router/java/src/net/i2p/data/i2np/GarlicMessage.java b/router/java/src/net/i2p/data/i2np/GarlicMessage.java index 2971abc7b..21d802184 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicMessage.java +++ b/router/java/src/net/i2p/data/i2np/GarlicMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -15,6 +15,7 @@ import java.io.InputStream; import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines the wrapped garlic message @@ -26,33 +27,34 @@ public class GarlicMessage extends I2NPMessageImpl { public final static int MESSAGE_TYPE = 11; private byte[] _data; - public GarlicMessage() { - setData(null); + public GarlicMessage(I2PAppContext context) { + super(context); + setData(null); } public byte[] getData() { return _data; } public void setData(byte[] data) { _data = data; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - long len = DataHelper.readLong(in, 4); - _data = new byte[(int)len]; - int read = read(in, _data); - if (read != len) - throw new I2NPMessageException("Incorrect size read"); + long len = DataHelper.readLong(in, 4); + _data = new byte[(int)len]; + int read = read(in, _data); + if (read != len) + throw new I2NPMessageException("Incorrect size read"); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if ( (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out"); - + if ( (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out"); + ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - DataHelper.writeLong(os, 4, _data.length); - os.write(_data); + DataHelper.writeLong(os, 4, _data.length); + os.write(_data); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -62,7 +64,7 @@ public class GarlicMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(getData()); + return DataHelper.hashCode(getData()); } public boolean equals(Object object) { @@ -74,7 +76,7 @@ public class GarlicMessage extends I2NPMessageImpl { } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[GarlicMessage: "); buf.append("\n\tData length: ").append(getData().length).append(" bytes"); diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java index 196311610..aea8e2e99 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -16,20 +16,25 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.util.Clock; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Handle messages from router to router * */ public class I2NPMessageHandler { - private final static Log _log = new Log(I2NPMessageHandler.class); + private Log _log; + private I2PAppContext _context; private long _lastReadBegin; private long _lastReadEnd; - public I2NPMessageHandler() {} + public I2NPMessageHandler(I2PAppContext context) { + _context = context; + _log = context.logManager().getLog(I2NPMessageHandler.class); + } /** * Read an I2NPMessage from the stream and return the fully populated object. - * + * * @throws IOException if there is an IO problem reading from the stream * @throws I2NPMessageException if there is a problem handling the particular * message - if it is an unknown type or has improper formatting, etc. @@ -37,10 +42,10 @@ public class I2NPMessageHandler { public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException { try { int type = (int)DataHelper.readLong(in, 1); - _lastReadBegin = Clock.getInstance().now(); + _lastReadBegin = System.currentTimeMillis(); I2NPMessage msg = createMessage(in, type); msg.readBytes(in, type); - _lastReadEnd = Clock.getInstance().now(); + _lastReadEnd = System.currentTimeMillis(); return msg; } catch (DataFormatException dfe) { throw new I2NPMessageException("Error reading the message", dfe); @@ -50,31 +55,31 @@ public class I2NPMessageHandler { public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; } /** - * Yes, this is fairly ugly, but its the only place it ever happens. + * Yes, this is fairly ugly, but its the only place it ever happens. * */ - private static I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException { + private I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException { switch (type) { - case DatabaseStoreMessage.MESSAGE_TYPE: - return new DatabaseStoreMessage(); - case DatabaseLookupMessage.MESSAGE_TYPE: - return new DatabaseLookupMessage(); - case DatabaseSearchReplyMessage.MESSAGE_TYPE: - return new DatabaseSearchReplyMessage(); - case DeliveryStatusMessage.MESSAGE_TYPE: - return new DeliveryStatusMessage(); - case GarlicMessage.MESSAGE_TYPE: - return new GarlicMessage(); - case TunnelMessage.MESSAGE_TYPE: - return new TunnelMessage(); - case DataMessage.MESSAGE_TYPE: - return new DataMessage(); - case SourceRouteReplyMessage.MESSAGE_TYPE: - return new SourceRouteReplyMessage(); - case TunnelCreateMessage.MESSAGE_TYPE: - return new TunnelCreateMessage(); - case TunnelCreateStatusMessage.MESSAGE_TYPE: - return new TunnelCreateStatusMessage(); + case DatabaseStoreMessage.MESSAGE_TYPE: + return new DatabaseStoreMessage(_context); + case DatabaseLookupMessage.MESSAGE_TYPE: + return new DatabaseLookupMessage(_context); + case DatabaseSearchReplyMessage.MESSAGE_TYPE: + return new DatabaseSearchReplyMessage(_context); + case DeliveryStatusMessage.MESSAGE_TYPE: + return new DeliveryStatusMessage(_context); + case GarlicMessage.MESSAGE_TYPE: + return new GarlicMessage(_context); + case TunnelMessage.MESSAGE_TYPE: + return new TunnelMessage(_context); + case DataMessage.MESSAGE_TYPE: + return new DataMessage(_context); + case SourceRouteReplyMessage.MESSAGE_TYPE: + return new SourceRouteReplyMessage(_context); + case TunnelCreateMessage.MESSAGE_TYPE: + return new TunnelCreateMessage(_context); + case TunnelCreateStatusMessage.MESSAGE_TYPE: + return new TunnelCreateStatusMessage(_context); default: throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message"); } @@ -82,7 +87,7 @@ public class I2NPMessageHandler { public static void main(String args[]) { try { - I2NPMessage msg = new I2NPMessageHandler().readMessage(new FileInputStream(args[0])); + I2NPMessage msg = new I2NPMessageHandler(I2PAppContext.getGlobalContext()).readMessage(new FileInputStream(args[0])); System.out.println(msg); } catch (Exception e) { e.printStackTrace(); diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 581d89a61..f36a7fb63 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -19,6 +19,7 @@ import net.i2p.data.DataStructureImpl; import net.i2p.util.Clock; import net.i2p.util.Log; import net.i2p.util.RandomSource; +import net.i2p.I2PAppContext; /** * Defines the base message implementation. @@ -26,15 +27,18 @@ import net.i2p.util.RandomSource; * @author jrandom */ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPMessage { - private final static Log _log = new Log(I2NPMessageImpl.class); + private Log _log; + protected I2PAppContext _context; private Date _expiration; private long _uniqueId; public final static long DEFAULT_EXPIRATION_MS = 1*60*1000; // 1 minute by default - public I2NPMessageImpl() { - _expiration = new Date(Clock.getInstance().now() + DEFAULT_EXPIRATION_MS); - _uniqueId = RandomSource.getInstance().nextInt(Integer.MAX_VALUE); + public I2NPMessageImpl(I2PAppContext context) { + _context = context; + _log = context.logManager().getLog(I2NPMessageImpl.class); + _expiration = new Date(_context.clock().now() + DEFAULT_EXPIRATION_MS); + _uniqueId = _context.random().nextInt(Integer.MAX_VALUE); } /** @@ -45,8 +49,8 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM protected abstract byte[] writeMessage() throws I2NPMessageException, IOException; /** - * Read the body into the data structures, after the initial type byte and - * the uniqueId / expiration, using the current class's format as defined by + * Read the body into the data structures, after the initial type byte and + * the uniqueId / expiration, using the current class's format as defined by * the I2NP specification * * @param in stream to read from @@ -58,35 +62,35 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM protected abstract void readMessage(InputStream in, int type) throws I2NPMessageException, IOException; public void readBytes(InputStream in) throws DataFormatException, IOException { - try { - readBytes(in, -1); - } catch (I2NPMessageException ime) { - throw new DataFormatException("Bad bytes", ime); - } + try { + readBytes(in, -1); + } catch (I2NPMessageException ime) { + throw new DataFormatException("Bad bytes", ime); + } } public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException { - try { - if (type < 0) - type = (int)DataHelper.readLong(in, 1); - _uniqueId = DataHelper.readLong(in, 4); - _expiration = DataHelper.readDate(in); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Error reading the message header", dfe); - } - _log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); - readMessage(in, type); + try { + if (type < 0) + type = (int)DataHelper.readLong(in, 1); + _uniqueId = DataHelper.readLong(in, 4); + _expiration = DataHelper.readDate(in); + } catch (DataFormatException dfe) { + throw new I2NPMessageException("Error reading the message header", dfe); + } + _log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); + readMessage(in, type); } public void writeBytes(OutputStream out) throws DataFormatException, IOException { - try { - DataHelper.writeLong(out, 1, getType()); - DataHelper.writeLong(out, 4, _uniqueId); - DataHelper.writeDate(out, _expiration); - _log.debug("Writing bytes: type = " + getType() + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); - byte[] data = writeMessage(); - out.write(data); - } catch (I2NPMessageException ime) { - throw new DataFormatException("Error writing out the I2NP message data", ime); - } + try { + DataHelper.writeLong(out, 1, getType()); + DataHelper.writeLong(out, 4, _uniqueId); + DataHelper.writeDate(out, _expiration); + _log.debug("Writing bytes: type = " + getType() + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); + byte[] data = writeMessage(); + out.write(data); + } catch (I2NPMessageException ime) { + throw new DataFormatException("Error writing out the I2NP message data", ime); + } } /** diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java b/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java index 140e98a52..f34420c98 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageReader.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -13,9 +13,10 @@ import java.io.InputStream; import net.i2p.util.I2PThread; import net.i2p.util.Log; +import net.i2p.router.RouterContext; /** - * The I2NPMessageReader reads an InputStream (using + * The I2NPMessageReader reads an InputStream (using * {@link I2NPMessageHandler I2NPMessageHandler}) and passes out events to a registered * listener, where events are either messages being received, exceptions being * thrown, or the connection being closed. Routers should use this rather @@ -24,23 +25,26 @@ import net.i2p.util.Log; * @author jrandom */ public class I2NPMessageReader { - private final static Log _log = new Log(I2NPMessageReader.class); + private Log _log; + private RouterContext _context; private InputStream _stream; private I2NPMessageEventListener _listener; private I2NPMessageReaderRunner _reader; private Thread _readerThread; - public I2NPMessageReader(InputStream stream, I2NPMessageEventListener lsnr) { - this(stream, lsnr, "I2NP Reader"); + public I2NPMessageReader(RouterContext context, InputStream stream, I2NPMessageEventListener lsnr) { + this(context, stream, lsnr, "I2NP Reader"); } - public I2NPMessageReader(InputStream stream, I2NPMessageEventListener lsnr, String name) { - _stream = stream; + public I2NPMessageReader(RouterContext context, InputStream stream, I2NPMessageEventListener lsnr, String name) { + _context = context; + _log = context.logManager().getLog(I2NPMessageReader.class); + _stream = stream; setListener(lsnr); _reader = new I2NPMessageReaderRunner(); _readerThread = new I2PThread(_reader); - _readerThread.setName(name); - _readerThread.setDaemon(true); + _readerThread.setName(name); + _readerThread.setDaemon(true); } public void setListener(I2NPMessageEventListener lsnr) { _listener = lsnr; } @@ -50,7 +54,7 @@ public class I2NPMessageReader { * Instruct the reader to begin reading messages off the stream * */ - public void startReading() { _readerThread.start(); } + public void startReading() { _readerThread.start(); } /** * Have the already started reader pause its reading indefinitely * @@ -62,7 +66,7 @@ public class I2NPMessageReader { */ public void resumeReading() { _reader.resumeRunner(); } /** - * Cancel reading. + * Cancel reading. * */ public void stopReading() { _reader.cancelRunner(); } @@ -90,22 +94,22 @@ public class I2NPMessageReader { * */ public void disconnected(I2NPMessageReader reader); - } + } private class I2NPMessageReaderRunner implements Runnable { - private boolean _doRun; + private boolean _doRun; private boolean _stayAlive; - private I2NPMessageHandler _handler; + private I2NPMessageHandler _handler; public I2NPMessageReaderRunner() { _doRun = true; _stayAlive = true; - _handler = new I2NPMessageHandler(); + _handler = new I2NPMessageHandler(_context); } public void pauseRunner() { _doRun = false; } public void resumeRunner() { _doRun = true; } - public void cancelRunner() { + public void cancelRunner() { _doRun = false; - _stayAlive = false; + _stayAlive = false; } public void run() { while (_stayAlive) { @@ -114,16 +118,16 @@ public class I2NPMessageReader { try { I2NPMessage msg = _handler.readMessage(_stream); if (msg != null) { - long msToRead = _handler.getLastReadTime(); + long msToRead = _handler.getLastReadTime(); _listener.messageReceived(I2NPMessageReader.this, msg, msToRead); - } + } } catch (I2NPMessageException ime) { - //_log.warn("Error handling message", ime); + //_log.warn("Error handling message", ime); _listener.readError(I2NPMessageReader.this, ime); - _listener.disconnected(I2NPMessageReader.this); - cancelRunner(); + _listener.disconnected(I2NPMessageReader.this); + cancelRunner(); } catch (IOException ioe) { - _log.warn("IO Error handling message", ioe); + _log.warn("IO Error handling message", ioe); _listener.disconnected(I2NPMessageReader.this); cancelRunner(); } diff --git a/router/java/src/net/i2p/data/i2np/SourceRouteBlock.java b/router/java/src/net/i2p/data/i2np/SourceRouteBlock.java index 58f1de654..42eadfc06 100644 --- a/router/java/src/net/i2p/data/i2np/SourceRouteBlock.java +++ b/router/java/src/net/i2p/data/i2np/SourceRouteBlock.java @@ -26,6 +26,7 @@ import net.i2p.data.PublicKey; import net.i2p.data.SessionKey; import net.i2p.data.SessionTag; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** @@ -46,14 +47,14 @@ public class SourceRouteBlock extends DataStructureImpl { private long _decryptedExpiration; public SourceRouteBlock() { - setRouter(null); - setData(null); - setKey(null); - setTag((byte[])null); - _decryptedInstructions = null; - _decryptedMessageId = -1; - _decryptedCertificate = null; - _decryptedExpiration = -1; + setRouter(null); + setData(null); + setKey(null); + setTag((byte[])null); + _decryptedInstructions = null; + _decryptedMessageId = -1; + _decryptedCertificate = null; + _decryptedExpiration = -1; } /** @@ -92,9 +93,9 @@ public class SourceRouteBlock extends DataStructureImpl { public byte[] getTag() { return _tag; } public void setTag(SessionTag tag) { setTag(tag.getData()); } public void setTag(byte tag[]) { - if ( (tag != null) && (tag.length != SessionTag.BYTE_LENGTH) ) - throw new IllegalArgumentException("Tag must be either null or 32 bytes"); - _tag = tag; + if ( (tag != null) && (tag.length != SessionTag.BYTE_LENGTH) ) + throw new IllegalArgumentException("Tag must be either null or 32 bytes"); + _tag = tag; } /** @@ -126,100 +127,105 @@ public class SourceRouteBlock extends DataStructureImpl { * * @throws DataFormatException if the data is invalid or could not be encrypted */ - public void setData(DeliveryInstructions instructions, long messageId, Certificate cert, long expiration, PublicKey replyThrough) throws DataFormatException { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(64); + public void setData(I2PAppContext ctx, DeliveryInstructions instructions, + long messageId, Certificate cert, long expiration, + PublicKey replyThrough) throws DataFormatException { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(64); - _decryptedInstructions = instructions; - _decryptedMessageId = messageId; - _decryptedCertificate = cert; - _decryptedExpiration = expiration; - - instructions.writeBytes(baos); - DataHelper.writeLong(baos, 4, messageId); - cert.writeBytes(baos); - DataHelper.writeDate(baos, new Date(expiration)); + _decryptedInstructions = instructions; + _decryptedMessageId = messageId; + _decryptedCertificate = cert; + _decryptedExpiration = expiration; - int paddedSize = 256; - SessionKey sessKey = null; - SessionTag tag = null; - if (instructions.getDelayRequested()) { - // always use a new key if we're delaying, since the reply block may not be used within the - // window of a session - sessKey = KeyGenerator.getInstance().generateSessionKey(); - tag = null; - _log.debug("Delay requested - creating a new session key"); - } else { - sessKey = SessionKeyManager.getInstance().getCurrentKey(replyThrough); - if (sessKey == null) { - sessKey = KeyGenerator.getInstance().generateSessionKey(); - tag = null; - _log.debug("No delay requested, but no session key is known"); - } else { - tag = SessionKeyManager.getInstance().consumeNextAvailableTag(replyThrough, sessKey); - } - } - byte encData[] = ElGamalAESEngine.encrypt(baos.toByteArray(), replyThrough, sessKey, null, tag, paddedSize); - setData(encData); - } catch (IOException ioe) { - throw new DataFormatException("Error writing out the source route block data", ioe); - } catch (DataFormatException dfe) { - throw new DataFormatException("Error writing out the source route block data", dfe); - } + instructions.writeBytes(baos); + DataHelper.writeLong(baos, 4, messageId); + cert.writeBytes(baos); + DataHelper.writeDate(baos, new Date(expiration)); + + int paddedSize = 256; + SessionKey sessKey = null; + SessionTag tag = null; + if (instructions.getDelayRequested()) { + // always use a new key if we're delaying, since the reply block may not be used within the + // window of a session + sessKey = ctx.keyGenerator().generateSessionKey(); + tag = null; + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Delay requested - creating a new session key"); + } else { + sessKey = ctx.sessionKeyManager().getCurrentKey(replyThrough); + if (sessKey == null) { + sessKey = ctx.keyGenerator().generateSessionKey(); + tag = null; + if (_log.shouldLog(Log.DEBUG)) + _log.debug("No delay requested, but no session key is known"); + } else { + tag = ctx.sessionKeyManager().consumeNextAvailableTag(replyThrough, sessKey); + } + } + byte encData[] = ctx.elGamalAESEngine().encrypt(baos.toByteArray(), replyThrough, + sessKey, null, tag, paddedSize); + setData(encData); + } catch (IOException ioe) { + throw new DataFormatException("Error writing out the source route block data", ioe); + } catch (DataFormatException dfe) { + throw new DataFormatException("Error writing out the source route block data", dfe); + } } public void readBytes(InputStream in) throws DataFormatException, IOException { - _router = new Hash(); - _router.readBytes(in); - int size = (int)DataHelper.readLong(in, 2); - _data = new byte[size]; - int read = read(in, _data); - if (read != _data.length) - throw new DataFormatException("Incorrect # of bytes read for source route block: " + read); - _key = new SessionKey(); - _key.readBytes(in); - _tag = new byte[32]; - read = read(in, _tag); - if (read != _tag.length) - throw new DataFormatException("Incorrect # of bytes read for session tag: " + read); + _router = new Hash(); + _router.readBytes(in); + int size = (int)DataHelper.readLong(in, 2); + _data = new byte[size]; + int read = read(in, _data); + if (read != _data.length) + throw new DataFormatException("Incorrect # of bytes read for source route block: " + read); + _key = new SessionKey(); + _key.readBytes(in); + _tag = new byte[32]; + read = read(in, _tag); + if (read != _tag.length) + throw new DataFormatException("Incorrect # of bytes read for session tag: " + read); } public void writeBytes(OutputStream out) throws DataFormatException, IOException { if ( (_router == null) || (_data == null) || (_key == null) || (_tag == null) || (_tag.length != 32) ) - throw new DataFormatException("Insufficient data to write"); - _router.writeBytes(out); - DataHelper.writeLong(out, 2, _data.length); - out.write(_data); - _key.writeBytes(out); - out.write(_tag); + throw new DataFormatException("Insufficient data to write"); + _router.writeBytes(out); + DataHelper.writeLong(out, 2, _data.length); + out.write(_data); + _key.writeBytes(out); + out.write(_tag); } public boolean equals(Object obj) { if ( (obj == null) || !(obj instanceof SourceRouteBlock)) return false; - SourceRouteBlock block = (SourceRouteBlock)obj; - return DataHelper.eq(getRouter(), block.getRouter()) && - DataHelper.eq(getData(), block.getData()) && - DataHelper.eq(getKey(), block.getKey()) && - DataHelper.eq(getTag(), block.getTag()); + SourceRouteBlock block = (SourceRouteBlock)obj; + return DataHelper.eq(getRouter(), block.getRouter()) && + DataHelper.eq(getData(), block.getData()) && + DataHelper.eq(getKey(), block.getKey()) && + DataHelper.eq(getTag(), block.getTag()); } public int hashCode() { return DataHelper.hashCode(getRouter()) + - DataHelper.hashCode(getData()) + - DataHelper.hashCode(getKey()) + - DataHelper.hashCode(getTag()); + DataHelper.hashCode(getData()) + + DataHelper.hashCode(getKey()) + + DataHelper.hashCode(getTag()); } public String toString() { - StringBuffer buf = new StringBuffer(128); + StringBuffer buf = new StringBuffer(128); buf.append("[SourceRouteBlock: "); - buf.append("\n\tRouter: ").append(getRouter()); - buf.append("\n\tData: ").append(DataHelper.toString(getData(), getData().length)); - buf.append("\n\tTag: ").append(DataHelper.toString(getTag(), (getTag() != null ? getTag().length : 0))); - buf.append("\n\tKey: ").append(getKey()); - buf.append("]"); - return buf.toString(); + buf.append("\n\tRouter: ").append(getRouter()); + buf.append("\n\tData: ").append(DataHelper.toString(getData(), getData().length)); + buf.append("\n\tTag: ").append(DataHelper.toString(getTag(), (getTag() != null ? getTag().length : 0))); + buf.append("\n\tKey: ").append(getKey()); + buf.append("]"); + return buf.toString(); } } diff --git a/router/java/src/net/i2p/data/i2np/SourceRouteReplyMessage.java b/router/java/src/net/i2p/data/i2np/SourceRouteReplyMessage.java index 017ee6bb2..29c356469 100644 --- a/router/java/src/net/i2p/data/i2np/SourceRouteReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/SourceRouteReplyMessage.java @@ -19,6 +19,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.PrivateKey; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines a message directed by a source route block to deliver a message to an @@ -35,14 +36,17 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl { private long _decryptedMessageId; private Certificate _decryptedCertificate; private long _decryptedExpiration; + private I2NPMessageHandler _handler; - public SourceRouteReplyMessage() { - _encryptedHeader = null; - _message = null; - _decryptedInstructions = null; - _decryptedMessageId = -1; - _decryptedCertificate = null; - _decryptedExpiration = -1; + public SourceRouteReplyMessage(I2PAppContext context) { + super(context); + _handler = new I2NPMessageHandler(context); + _encryptedHeader = null; + _message = null; + _decryptedInstructions = null; + _decryptedMessageId = -1; + _decryptedCertificate = null; + _decryptedExpiration = -1; } /** @@ -77,54 +81,56 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl { * @throws DataFormatException if the decryption fails or if the data is somehow malformed */ public void decryptHeader(PrivateKey key) throws DataFormatException { - if ( (_encryptedHeader == null) || (_encryptedHeader.length <= 0) ) - throw new DataFormatException("No header to decrypt"); - - byte decr[] = ElGamalAESEngine.decrypt(_encryptedHeader, key); - - if (decr == null) - throw new DataFormatException("Decrypted data is null"); - - try { - ByteArrayInputStream bais = new ByteArrayInputStream(decr); - - _decryptedInstructions = new DeliveryInstructions(); - _decryptedInstructions.readBytes(bais); - _decryptedMessageId = DataHelper.readLong(bais, 4); - _decryptedCertificate = new Certificate(); - _decryptedCertificate.readBytes(bais); - _decryptedExpiration = DataHelper.readDate(bais).getTime(); + if ( (_encryptedHeader == null) || (_encryptedHeader.length <= 0) ) + throw new DataFormatException("No header to decrypt"); - } catch (IOException ioe) { - throw new DataFormatException("Error reading the source route reply header", ioe); - } catch (DataFormatException dfe) { - throw new DataFormatException("Error reading the source route reply header", dfe); - } + byte decr[] = _context.elGamalAESEngine().decrypt(_encryptedHeader, key); + + if (decr == null) + throw new DataFormatException("Decrypted data is null"); + + try { + ByteArrayInputStream bais = new ByteArrayInputStream(decr); + + _decryptedInstructions = new DeliveryInstructions(); + _decryptedInstructions.readBytes(bais); + _decryptedMessageId = DataHelper.readLong(bais, 4); + _decryptedCertificate = new Certificate(); + _decryptedCertificate.readBytes(bais); + _decryptedExpiration = DataHelper.readDate(bais).getTime(); + + } catch (IOException ioe) { + throw new DataFormatException("Error reading the source route reply header", ioe); + } catch (DataFormatException dfe) { + throw new DataFormatException("Error reading the source route reply header", dfe); + } } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) + throw new I2NPMessageException("Message type is incorrect for this message"); try { - int headerSize = (int)DataHelper.readLong(in, 2); - _encryptedHeader = new byte[headerSize]; - int read = read(in, _encryptedHeader); - if (read != headerSize) - throw new DataFormatException("Not enough bytes to read the header (read = " + read + ", required = " + headerSize + ")"); - _message = new I2NPMessageHandler().readMessage(in); + int headerSize = (int)DataHelper.readLong(in, 2); + _encryptedHeader = new byte[headerSize]; + int read = read(in, _encryptedHeader); + if (read != headerSize) + throw new DataFormatException("Not enough bytes to read the header (read = " + read + + ", required = " + headerSize + ")"); + _message = _handler.readMessage(in); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if ( (_encryptedHeader == null) || (_message == null) ) - throw new I2NPMessageException("Not enough data to write out"); - - ByteArrayOutputStream os = new ByteArrayOutputStream(1024); + if ( (_encryptedHeader == null) || (_message == null) ) + throw new I2NPMessageException("Not enough data to write out"); + + ByteArrayOutputStream os = new ByteArrayOutputStream(1024); try { - DataHelper.writeLong(os, 2, _encryptedHeader.length); - os.write(_encryptedHeader); - _message.writeBytes(os); + DataHelper.writeLong(os, 2, _encryptedHeader.length); + os.write(_encryptedHeader); + _message.writeBytes(os); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -134,15 +140,15 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(_encryptedHeader) + - DataHelper.hashCode(_message); + return DataHelper.hashCode(_encryptedHeader) + + DataHelper.hashCode(_message); } public boolean equals(Object object) { if ( (object != null) && (object instanceof SourceRouteReplyMessage) ) { SourceRouteReplyMessage msg = (SourceRouteReplyMessage)object; return DataHelper.eq(_message,msg._message) && - DataHelper.eq(_encryptedHeader,msg._encryptedHeader); + DataHelper.eq(_encryptedHeader,msg._encryptedHeader); } else { return false; } diff --git a/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java b/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java index b6f851646..857b0517f 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -18,6 +18,7 @@ import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.TunnelId; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines the message sent to a router to request that it participate in a @@ -52,23 +53,24 @@ public class TunnelCreateMessage extends I2NPMessageImpl { private final static long FLAG_DUMMY = 1 << 7; private final static long FLAG_REORDER = 1 << 6; - public TunnelCreateMessage() { - setParticipantType(-1); - setNextRouter(null); - setTunnelId(null); - setTunnelDurationSeconds(-1); - setConfigurationKey(null); - setMaxPeakMessagesPerMin(-1); - setMaxAvgMessagesPerMin(-1); - setMaxPeakBytesPerMin(-1); - setMaxAvgBytesPerMin(-1); - setIncludeDummyTraffic(false); - setReorderMessages(false); - setVerificationPublicKey(null); - setVerificationPrivateKey(null); - setTunnelKey(null); - setCertificate(null); - setReplyBlock(null); + public TunnelCreateMessage(I2PAppContext context) { + super(context); + setParticipantType(-1); + setNextRouter(null); + setTunnelId(null); + setTunnelDurationSeconds(-1); + setConfigurationKey(null); + setMaxPeakMessagesPerMin(-1); + setMaxAvgMessagesPerMin(-1); + setMaxPeakBytesPerMin(-1); + setMaxAvgBytesPerMin(-1); + setIncludeDummyTraffic(false); + setReorderMessages(false); + setVerificationPublicKey(null); + setVerificationPrivateKey(null); + setTunnelKey(null); + setCertificate(null); + setReplyBlock(null); } public void setParticipantType(int type) { _participantType = type; } @@ -105,41 +107,41 @@ public class TunnelCreateMessage extends I2NPMessageImpl { public SourceRouteBlock getReplyBlock() { return _replyBlock; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _participantType = (int)DataHelper.readLong(in, 1); - if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { - _nextRouter = new Hash(); - _nextRouter.readBytes(in); - } - _tunnelId = new TunnelId(); - _tunnelId.readBytes(in); - _tunnelDuration = DataHelper.readLong(in, 4); - _configKey = new TunnelConfigurationSessionKey(); - _configKey.readBytes(in); - _maxPeakMessagesPerMin = DataHelper.readLong(in, 4); - _maxAvgMessagesPerMin = DataHelper.readLong(in, 4); - _maxPeakBytesPerMin = DataHelper.readLong(in, 4); - _maxAvgBytesPerMin = DataHelper.readLong(in, 4); - - int flags = (int)DataHelper.readLong(in, 1); - _includeDummyTraffic = flagsIncludeDummy(flags); - _reorderMessages = flagsReorder(flags); - - _verificationPubKey = new TunnelSigningPublicKey(); - _verificationPubKey.readBytes(in); - if (_participantType == PARTICIPANT_TYPE_GATEWAY) { - _verificationPrivKey = new TunnelSigningPrivateKey(); - _verificationPrivKey.readBytes(in); - } - if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { - _tunnelKey = new TunnelSessionKey(); - _tunnelKey.readBytes(in); - } - _certificate = new Certificate(); - _certificate.readBytes(in); - _replyBlock = new SourceRouteBlock(); - _replyBlock.readBytes(in); + _participantType = (int)DataHelper.readLong(in, 1); + if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { + _nextRouter = new Hash(); + _nextRouter.readBytes(in); + } + _tunnelId = new TunnelId(); + _tunnelId.readBytes(in); + _tunnelDuration = DataHelper.readLong(in, 4); + _configKey = new TunnelConfigurationSessionKey(); + _configKey.readBytes(in); + _maxPeakMessagesPerMin = DataHelper.readLong(in, 4); + _maxAvgMessagesPerMin = DataHelper.readLong(in, 4); + _maxPeakBytesPerMin = DataHelper.readLong(in, 4); + _maxAvgBytesPerMin = DataHelper.readLong(in, 4); + + int flags = (int)DataHelper.readLong(in, 1); + _includeDummyTraffic = flagsIncludeDummy(flags); + _reorderMessages = flagsReorder(flags); + + _verificationPubKey = new TunnelSigningPublicKey(); + _verificationPubKey.readBytes(in); + if (_participantType == PARTICIPANT_TYPE_GATEWAY) { + _verificationPrivKey = new TunnelSigningPrivateKey(); + _verificationPrivKey.readBytes(in); + } + if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { + _tunnelKey = new TunnelSessionKey(); + _tunnelKey.readBytes(in); + } + _certificate = new Certificate(); + _certificate.readBytes(in); + _replyBlock = new SourceRouteBlock(); + _replyBlock.readBytes(in); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } @@ -148,146 +150,99 @@ public class TunnelCreateMessage extends I2NPMessageImpl { protected byte[] writeMessage() throws I2NPMessageException, IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - DataHelper.writeLong(os, 1, _participantType); - if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { - _nextRouter.writeBytes(os); - } - _tunnelId.writeBytes(os); - DataHelper.writeLong(os, 4, _tunnelDuration); - _configKey.writeBytes(os); - - DataHelper.writeLong(os, 4, _maxPeakMessagesPerMin); - DataHelper.writeLong(os, 4, _maxAvgMessagesPerMin); - DataHelper.writeLong(os, 4, _maxPeakBytesPerMin); - DataHelper.writeLong(os, 4, _maxAvgBytesPerMin); - - long flags = getFlags(); - DataHelper.writeLong(os, 1, flags); - - _verificationPubKey.writeBytes(os); - if (_participantType == PARTICIPANT_TYPE_GATEWAY) { - _verificationPrivKey.writeBytes(os); - } - if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { - _tunnelKey.writeBytes(os); - } - _certificate.writeBytes(os); - _replyBlock.writeBytes(os); + DataHelper.writeLong(os, 1, _participantType); + if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { + _nextRouter.writeBytes(os); + } + _tunnelId.writeBytes(os); + DataHelper.writeLong(os, 4, _tunnelDuration); + _configKey.writeBytes(os); + + DataHelper.writeLong(os, 4, _maxPeakMessagesPerMin); + DataHelper.writeLong(os, 4, _maxAvgMessagesPerMin); + DataHelper.writeLong(os, 4, _maxPeakBytesPerMin); + DataHelper.writeLong(os, 4, _maxAvgBytesPerMin); + + long flags = getFlags(); + DataHelper.writeLong(os, 1, flags); + + _verificationPubKey.writeBytes(os); + if (_participantType == PARTICIPANT_TYPE_GATEWAY) { + _verificationPrivKey.writeBytes(os); + } + if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { + _tunnelKey.writeBytes(os); + } + _certificate.writeBytes(os); + _replyBlock.writeBytes(os); } catch (Throwable t) { throw new I2NPMessageException("Error writing out the message data", t); } - /* - try { - DataHelper.writeLong(os, 1, _participantType); - if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { - if (_nextRouter == null) - throw new I2NPMessageException("Next router is not defined"); - _nextRouter.writeBytes(os); - } - if (_tunnelId == null) - throw new I2NPMessageException("Tunnel ID is not defined"); - _tunnelId.writeBytes(os); - if (_tunnelDuration < 0) - throw new I2NPMessageException("Tunnel duration is negative"); - DataHelper.writeLong(os, 4, _tunnelDuration); - if (_configKey == null) - throw new I2NPMessageException("Configuration key is not defined"); - _configKey.writeBytes(os); - if ( (_maxPeakMessagesPerMin < 0) || (_maxAvgMessagesPerMin < 0) || - (_maxAvgMessagesPerMin < 0) || (_maxAvgBytesPerMin < 0) ) - throw new I2NPMessageException("Negative limits defined"); - - long flags = getFlags(); - DataHelper.writeLong(os, 1, flags); - - if (_verificationPubKey == null) - throw new I2NPMessageException("Verification public key is not defined"); - _verificationPubKey.writeBytes(os); - if (_participantType == PARTICIPANT_TYPE_GATEWAY) { - if (_verificationPrivKey == null) - throw new I2NPMessageException("Verification private key is needed and not defined"); - _verificationPrivKey.writeBytes(os); - } - if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { - if (_tunnelKey == null) - throw new I2NPMessageException("Tunnel key is needed and not defined"); - _tunnelKey.writeBytes(os); - } - if (_certificate == null) - throw new I2NPMessageException("Certificate is not defined"); - _certificate.writeBytes(os); - if (_replyBlock == null) - throw new I2NPMessageException("Reply block not defined"); - _replyBlock.writeBytes(os); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Error writing out the message data", dfe); - } - */ return os.toByteArray(); } private boolean flagsIncludeDummy(long flags) { - return (0 != (flags & FLAG_DUMMY)); + return (0 != (flags & FLAG_DUMMY)); } private boolean flagsReorder(long flags) { - return (0 != (flags & FLAG_REORDER)); + return (0 != (flags & FLAG_REORDER)); } private long getFlags() { - long val = 0L; - if (getIncludeDummyTraffic()) - val = val | FLAG_DUMMY; - if (getReorderMessages()) - val = val | FLAG_REORDER; - return val; + long val = 0L; + if (getIncludeDummyTraffic()) + val = val | FLAG_DUMMY; + if (getReorderMessages()) + val = val | FLAG_REORDER; + return val; } public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return (int)(DataHelper.hashCode(getCertificate()) + - DataHelper.hashCode(getConfigurationKey()) + - DataHelper.hashCode(getNextRouter()) + - DataHelper.hashCode(getReplyBlock()) + - DataHelper.hashCode(getTunnelId()) + - DataHelper.hashCode(getTunnelKey()) + - DataHelper.hashCode(getVerificationPrivateKey()) + - DataHelper.hashCode(getVerificationPublicKey()) + - (getIncludeDummyTraffic() ? 1 : 0) + - getMaxAvgBytesPerMin() + - getMaxAvgMessagesPerMin() + - getMaxPeakBytesPerMin() + - getMaxPeakMessagesPerMin() + - getParticipantType() + - (getReorderMessages() ? 1 : 0) + - getTunnelDurationSeconds()); + return (int)(DataHelper.hashCode(getCertificate()) + + DataHelper.hashCode(getConfigurationKey()) + + DataHelper.hashCode(getNextRouter()) + + DataHelper.hashCode(getReplyBlock()) + + DataHelper.hashCode(getTunnelId()) + + DataHelper.hashCode(getTunnelKey()) + + DataHelper.hashCode(getVerificationPrivateKey()) + + DataHelper.hashCode(getVerificationPublicKey()) + + (getIncludeDummyTraffic() ? 1 : 0) + + getMaxAvgBytesPerMin() + + getMaxAvgMessagesPerMin() + + getMaxPeakBytesPerMin() + + getMaxPeakMessagesPerMin() + + getParticipantType() + + (getReorderMessages() ? 1 : 0) + + getTunnelDurationSeconds()); } public boolean equals(Object object) { if ( (object != null) && (object instanceof TunnelCreateMessage) ) { TunnelCreateMessage msg = (TunnelCreateMessage)object; - return DataHelper.eq(getCertificate(), msg.getCertificate()) && - DataHelper.eq(getConfigurationKey(), msg.getConfigurationKey()) && - DataHelper.eq(getNextRouter(), msg.getNextRouter()) && - DataHelper.eq(getReplyBlock(), msg.getReplyBlock()) && - DataHelper.eq(getTunnelId(), msg.getTunnelId()) && - DataHelper.eq(getTunnelKey(), msg.getTunnelKey()) && - DataHelper.eq(getVerificationPrivateKey(), msg.getVerificationPrivateKey()) && - DataHelper.eq(getVerificationPublicKey(), msg.getVerificationPublicKey()) && - (getIncludeDummyTraffic() == msg.getIncludeDummyTraffic()) && - (getMaxAvgBytesPerMin() == msg.getMaxAvgBytesPerMin()) && - (getMaxAvgMessagesPerMin() == msg.getMaxAvgMessagesPerMin()) && - (getMaxPeakBytesPerMin() == msg.getMaxPeakBytesPerMin()) && - (getMaxPeakMessagesPerMin() == msg.getMaxPeakMessagesPerMin()) && - (getParticipantType() == msg.getParticipantType()) && - (getReorderMessages() == msg.getReorderMessages()) && - (getTunnelDurationSeconds() == msg.getTunnelDurationSeconds()); + return DataHelper.eq(getCertificate(), msg.getCertificate()) && + DataHelper.eq(getConfigurationKey(), msg.getConfigurationKey()) && + DataHelper.eq(getNextRouter(), msg.getNextRouter()) && + DataHelper.eq(getReplyBlock(), msg.getReplyBlock()) && + DataHelper.eq(getTunnelId(), msg.getTunnelId()) && + DataHelper.eq(getTunnelKey(), msg.getTunnelKey()) && + DataHelper.eq(getVerificationPrivateKey(), msg.getVerificationPrivateKey()) && + DataHelper.eq(getVerificationPublicKey(), msg.getVerificationPublicKey()) && + (getIncludeDummyTraffic() == msg.getIncludeDummyTraffic()) && + (getMaxAvgBytesPerMin() == msg.getMaxAvgBytesPerMin()) && + (getMaxAvgMessagesPerMin() == msg.getMaxAvgMessagesPerMin()) && + (getMaxPeakBytesPerMin() == msg.getMaxPeakBytesPerMin()) && + (getMaxPeakMessagesPerMin() == msg.getMaxPeakMessagesPerMin()) && + (getParticipantType() == msg.getParticipantType()) && + (getReorderMessages() == msg.getReorderMessages()) && + (getTunnelDurationSeconds() == msg.getTunnelDurationSeconds()); } else { return false; } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[TunnelCreateMessage: "); buf.append("\n\tParticipant Type: ").append(getParticipantType()); diff --git a/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java b/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java index f18fc17b9..d8b276898 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -17,9 +17,10 @@ import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.TunnelId; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** - * Defines the message a router sends to another router in reply to a + * Defines the message a router sends to another router in reply to a * TunnelCreateMessage * * @author jrandom @@ -37,10 +38,11 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl { public final static int STATUS_FAILED_CERTIFICATE = 3; public final static int STATUS_FAILED_DELETED = 100; - public TunnelCreateStatusMessage() { - setTunnelId(null); - setStatus(-1); - setFromHash(null); + public TunnelCreateStatusMessage(I2PAppContext context) { + super(context); + setTunnelId(null); + setStatus(-1); + setFromHash(null); } public TunnelId getTunnelId() { return _tunnelId; } @@ -56,26 +58,26 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl { public void setFromHash(Hash from) { _from = from; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _tunnelId = new TunnelId(); - _tunnelId.readBytes(in); - _status = (int)DataHelper.readLong(in, 1); - _from = new Hash(); - _from.readBytes(in); + _tunnelId = new TunnelId(); + _tunnelId.readBytes(in); + _status = (int)DataHelper.readLong(in, 1); + _from = new Hash(); + _from.readBytes(in); } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out"); - + if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out"); + ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - _tunnelId.writeBytes(os); - DataHelper.writeLong(os, 1, (_status < 0 ? 255 : _status)); - _from.writeBytes(os); + _tunnelId.writeBytes(os); + DataHelper.writeLong(os, 1, (_status < 0 ? 255 : _status)); + _from.writeBytes(os); } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } @@ -85,23 +87,23 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl { public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(getTunnelId()) + - getStatus() + - DataHelper.hashCode(getFromHash()); + return DataHelper.hashCode(getTunnelId()) + + getStatus() + + DataHelper.hashCode(getFromHash()); } public boolean equals(Object object) { if ( (object != null) && (object instanceof TunnelCreateStatusMessage) ) { TunnelCreateStatusMessage msg = (TunnelCreateStatusMessage)object; return DataHelper.eq(getTunnelId(),msg.getTunnelId()) && - DataHelper.eq(getFromHash(),msg.getFromHash()) && - (getStatus() == msg.getStatus()); + DataHelper.eq(getFromHash(),msg.getFromHash()) && + (getStatus() == msg.getStatus()); } else { return false; } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[TunnelCreateStatusMessage: "); buf.append("\n\tTunnel ID: ").append(getTunnelId()); diff --git a/router/java/src/net/i2p/data/i2np/TunnelMessage.java b/router/java/src/net/i2p/data/i2np/TunnelMessage.java index 26aeb38dc..a723b2074 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelMessage.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -16,6 +16,7 @@ import net.i2p.data.DataFormatException; import net.i2p.data.DataHelper; import net.i2p.data.TunnelId; import net.i2p.util.Log; +import net.i2p.I2PAppContext; /** * Defines the message sent between routers for tunnel delivery @@ -34,11 +35,12 @@ public class TunnelMessage extends I2NPMessageImpl { private final static int FLAG_INCLUDESTRUCTURE = 0; private final static int FLAG_DONT_INCLUDESTRUCTURE = 1; - public TunnelMessage() { - setTunnelId(null); - setData(null); - setVerificationStructure(null); - setEncryptedDeliveryInstructions(null); + public TunnelMessage(I2PAppContext context) { + super(context); + setTunnelId(null); + setData(null); + setVerificationStructure(null); + setEncryptedDeliveryInstructions(null); } public TunnelId getTunnelId() { return _tunnelId; } @@ -54,85 +56,85 @@ public class TunnelMessage extends I2NPMessageImpl { public void setEncryptedDeliveryInstructions(byte instructions[]) { _encryptedInstructions = instructions; } public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { - if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); + if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); try { - _tunnelId = new TunnelId(); - _tunnelId.readBytes(in); - _log.debug("Read tunnel message for tunnel " + _tunnelId); - _size = DataHelper.readLong(in, 4); - _log.debug("Read tunnel message size: " + _size); - if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size); - _data = new byte[(int)_size]; - int read = read(in, _data); - if (read != _size) - throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size); - int includeVerification = (int)DataHelper.readLong(in, 1); - if (includeVerification == FLAG_INCLUDESTRUCTURE) { - _verification = new TunnelVerificationStructure(); - _verification.readBytes(in); - int len = (int)DataHelper.readLong(in, 2); - _encryptedInstructions = new byte[len]; - read = read(in, _encryptedInstructions); - if (read != len) - throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")"); - } + _tunnelId = new TunnelId(); + _tunnelId.readBytes(in); + _log.debug("Read tunnel message for tunnel " + _tunnelId); + _size = DataHelper.readLong(in, 4); + _log.debug("Read tunnel message size: " + _size); + if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size); + _data = new byte[(int)_size]; + int read = read(in, _data); + if (read != _size) + throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size); + int includeVerification = (int)DataHelper.readLong(in, 1); + if (includeVerification == FLAG_INCLUDESTRUCTURE) { + _verification = new TunnelVerificationStructure(); + _verification.readBytes(in); + int len = (int)DataHelper.readLong(in, 2); + _encryptedInstructions = new byte[len]; + read = read(in, _encryptedInstructions); + if (read != len) + throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")"); + } } catch (DataFormatException dfe) { throw new I2NPMessageException("Unable to load the message data", dfe); } } protected byte[] writeMessage() throws I2NPMessageException, IOException { - if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) ) - throw new I2NPMessageException("Not enough data to write out"); - + if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) ) + throw new I2NPMessageException("Not enough data to write out"); + ByteArrayOutputStream os = new ByteArrayOutputStream(32); try { - _tunnelId.writeBytes(os); - _log.debug("Writing tunnel message for tunnel " + _tunnelId); - DataHelper.writeLong(os, 4, _data.length); - _log.debug("Writing tunnel message length: " + _data.length); - os.write(_data); - _log.debug("Writing tunnel message data"); - if ( (_verification == null) || (_encryptedInstructions == null) ) { - DataHelper.writeLong(os, 1, FLAG_DONT_INCLUDESTRUCTURE); - _log.debug("Writing DontIncludeStructure flag"); - } else { - DataHelper.writeLong(os, 1, FLAG_INCLUDESTRUCTURE); - _log.debug("Writing IncludeStructure flag, then the verification structure, then the E(instr).length [" + _encryptedInstructions.length + "], then the E(instr)"); - _verification.writeBytes(os); - DataHelper.writeLong(os, 2, _encryptedInstructions.length); - os.write(_encryptedInstructions); - } + _tunnelId.writeBytes(os); + _log.debug("Writing tunnel message for tunnel " + _tunnelId); + DataHelper.writeLong(os, 4, _data.length); + _log.debug("Writing tunnel message length: " + _data.length); + os.write(_data); + _log.debug("Writing tunnel message data"); + if ( (_verification == null) || (_encryptedInstructions == null) ) { + DataHelper.writeLong(os, 1, FLAG_DONT_INCLUDESTRUCTURE); + _log.debug("Writing DontIncludeStructure flag"); + } else { + DataHelper.writeLong(os, 1, FLAG_INCLUDESTRUCTURE); + _log.debug("Writing IncludeStructure flag, then the verification structure, then the E(instr).length [" + _encryptedInstructions.length + "], then the E(instr)"); + _verification.writeBytes(os); + DataHelper.writeLong(os, 2, _encryptedInstructions.length); + os.write(_encryptedInstructions); + } } catch (DataFormatException dfe) { throw new I2NPMessageException("Error writing out the message data", dfe); } - byte rv[] = os.toByteArray(); - _log.debug("Overall data being written: " + rv.length); + byte rv[] = os.toByteArray(); + _log.debug("Overall data being written: " + rv.length); return rv; } public int getType() { return MESSAGE_TYPE; } public int hashCode() { - return DataHelper.hashCode(getTunnelId()) + - DataHelper.hashCode(_data) + - DataHelper.hashCode(getVerificationStructure()) + - DataHelper.hashCode(getEncryptedDeliveryInstructions()); + return DataHelper.hashCode(getTunnelId()) + + DataHelper.hashCode(_data) + + DataHelper.hashCode(getVerificationStructure()) + + DataHelper.hashCode(getEncryptedDeliveryInstructions()); } public boolean equals(Object object) { if ( (object != null) && (object instanceof TunnelMessage) ) { TunnelMessage msg = (TunnelMessage)object; return DataHelper.eq(getTunnelId(),msg.getTunnelId()) && - DataHelper.eq(getVerificationStructure(),msg.getVerificationStructure()) && - DataHelper.eq(getData(),msg.getData()) && - DataHelper.eq(getEncryptedDeliveryInstructions(), msg.getEncryptedDeliveryInstructions()); + DataHelper.eq(getVerificationStructure(),msg.getVerificationStructure()) && + DataHelper.eq(getData(),msg.getData()) && + DataHelper.eq(getEncryptedDeliveryInstructions(), msg.getEncryptedDeliveryInstructions()); } else { return false; } } - public String toString() { + public String toString() { StringBuffer buf = new StringBuffer(); buf.append("[TunnelMessage: "); buf.append("\n\tTunnel ID: ").append(getTunnelId()); diff --git a/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java b/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java index 8309e62b5..3fbcac128 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java +++ b/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java @@ -1,9 +1,9 @@ package net.i2p.data.i2np; /* * 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 + * 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. * */ @@ -21,19 +21,19 @@ import net.i2p.data.Signature; import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPublicKey; import net.i2p.util.Log; +import net.i2p.router.RouterContext; /** * * @author jrandom */ public class TunnelVerificationStructure extends DataStructureImpl { - private final static Log _log = new Log(TunnelVerificationStructure.class); private Hash _msgHash; private Signature _authSignature; - public TunnelVerificationStructure() { - setMessageHash(null); - setAuthorizationSignature(null); + public TunnelVerificationStructure() { + setMessageHash(null); + setAuthorizationSignature(null); } public Hash getMessageHash() { return _msgHash; } @@ -42,45 +42,45 @@ public class TunnelVerificationStructure extends DataStructureImpl { public Signature getAuthorizationSignature() { return _authSignature; } public void setAuthorizationSignature(Signature sig) { _authSignature = sig; } - public void sign(SigningPrivateKey key) { - if (_msgHash != null) { - Signature sig = DSAEngine.getInstance().sign(_msgHash.getData(), key); - setAuthorizationSignature(sig); - } + public void sign(RouterContext context, SigningPrivateKey key) { + if (_msgHash != null) { + Signature sig = context.dsa().sign(_msgHash.getData(), key); + setAuthorizationSignature(sig); + } } - public boolean verifySignature(SigningPublicKey key) { - if (_msgHash == null) return false; - return DSAEngine.getInstance().verifySignature(_authSignature, _msgHash.getData(), key); + public boolean verifySignature(RouterContext context, SigningPublicKey key) { + if (_msgHash == null) return false; + return context.dsa().verifySignature(_authSignature, _msgHash.getData(), key); } public void readBytes(InputStream in) throws DataFormatException, IOException { - _msgHash = new Hash(); - _msgHash.readBytes(in); - _authSignature = new Signature(); - _authSignature.readBytes(in); + _msgHash = new Hash(); + _msgHash.readBytes(in); + _authSignature = new Signature(); + _authSignature.readBytes(in); } public void writeBytes(OutputStream out) throws DataFormatException, IOException { - if (_authSignature == null) { - _authSignature = new Signature(); - _authSignature.setData(Signature.FAKE_SIGNATURE); - } + if (_authSignature == null) { + _authSignature = new Signature(); + _authSignature.setData(Signature.FAKE_SIGNATURE); + } if ( (_msgHash == null) || (_authSignature == null) ) throw new DataFormatException("Invalid data"); - _msgHash.writeBytes(out); - _authSignature.writeBytes(out); + _msgHash.writeBytes(out); + _authSignature.writeBytes(out); } public boolean equals(Object obj) { if ( (obj == null) || !(obj instanceof TunnelVerificationStructure)) return false; - TunnelVerificationStructure str = (TunnelVerificationStructure)obj; - return DataHelper.eq(getMessageHash(), str.getMessageHash()) && - DataHelper.eq(getAuthorizationSignature(), str.getAuthorizationSignature()); + TunnelVerificationStructure str = (TunnelVerificationStructure)obj; + return DataHelper.eq(getMessageHash(), str.getMessageHash()) && + DataHelper.eq(getAuthorizationSignature(), str.getAuthorizationSignature()); } public int hashCode() { - if ( (_msgHash == null) || (_authSignature == null) ) return 0; - return getMessageHash().hashCode() + getAuthorizationSignature().hashCode(); + if ( (_msgHash == null) || (_authSignature == null) ) return 0; + return getMessageHash().hashCode() + getAuthorizationSignature().hashCode(); } public String toString() { diff --git a/router/java/src/net/i2p/router/ClientManagerFacade.java b/router/java/src/net/i2p/router/ClientManagerFacade.java index 73d39024b..e44fd97cb 100644 --- a/router/java/src/net/i2p/router/ClientManagerFacade.java +++ b/router/java/src/net/i2p/router/ClientManagerFacade.java @@ -21,8 +21,6 @@ import net.i2p.router.client.ClientManagerFacadeImpl; * @author jrandom */ public abstract class ClientManagerFacade implements Service { - private static ClientManagerFacade _instance = new ClientManagerFacadeImpl(); - public static ClientManagerFacade getInstance() { return _instance; } /** * Request that a particular client authorize the Leases contained in the @@ -74,16 +72,19 @@ public abstract class ClientManagerFacade implements Service { } class DummyClientManagerFacade extends ClientManagerFacade { + private RouterContext _context; + public DummyClientManagerFacade(RouterContext ctx) { + _context = ctx; + } public boolean isLocal(Hash destHash) { return true; } public boolean isLocal(Destination dest) { return true; } public void reportAbuse(Destination dest, String reason, int severity) { } public void messageReceived(ClientMessage msg) {} - public void requestLeaseSet(Destination dest, LeaseSet set, long timeout, Job onCreateJob, Job onFailedJob) { - JobQueue.getInstance().addJob(onFailedJob); + public void requestLeaseSet(Destination dest, LeaseSet set, long timeout, + Job onCreateJob, Job onFailedJob) { + _context.jobQueue().addJob(onFailedJob); } - public void startup() { - //JobQueue.getInstance().addJob(new PollOutboundClientMessagesJob()); - } + public void startup() {} public void stopAcceptingClients() { } public void shutdown() {} diff --git a/router/java/src/net/i2p/router/ClientMessagePool.java b/router/java/src/net/i2p/router/ClientMessagePool.java index 05fd9d3c3..8abe694b3 100644 --- a/router/java/src/net/i2p/router/ClientMessagePool.java +++ b/router/java/src/net/i2p/router/ClientMessagePool.java @@ -25,15 +25,12 @@ import net.i2p.util.Log; * */ public class ClientMessagePool { - private final static Log _log = new Log(ClientMessagePool.class); - private static ClientMessagePool _instance = new ClientMessagePool(); - public static final ClientMessagePool getInstance() { return _instance; } - private List _inMessages; - private List _outMessages; + private Log _log; + private RouterContext _context; - private ClientMessagePool() { - _inMessages = new ArrayList(); - _outMessages = new ArrayList(); + public ClientMessagePool(RouterContext context) { + _context = context; + _log = _context.logManager().getLog(ClientMessagePool.class); } /** @@ -42,84 +39,13 @@ public class ClientMessagePool { * */ public void add(ClientMessage msg) { - if ( (ClientManagerFacade.getInstance().isLocal(msg.getDestination())) || - (ClientManagerFacade.getInstance().isLocal(msg.getDestinationHash())) ) { - _log.debug("Adding message for local delivery"); - ClientManagerFacade.getInstance().messageReceived(msg); - //synchronized (_inMessages) { - // _inMessages.add(msg); - //} - } else { - _log.debug("Adding message for remote delivery"); - //JobQueue.getInstance().addJob(new ProcessOutboundClientMessageJob(msg)); - JobQueue.getInstance().addJob(new OutboundClientMessageJob(msg)); - //synchronized (_outMessages) { - // _outMessages.add(msg); - //} - } - } - - /** - * Retrieve the next locally destined message, or null if none are available. - * - */ - public ClientMessage getNextLocal() { - synchronized (_inMessages) { - if (_inMessages.size() <= 0) return null; - return (ClientMessage)_inMessages.remove(0); - } - } - - /** - * Retrieve the next remotely destined message, or null if none are available. - * - */ - public ClientMessage getNextRemote() { - synchronized (_outMessages) { - if (_outMessages.size() <= 0) return null; - return (ClientMessage)_outMessages.remove(0); - } - } - - /** - * Determine how many locally bound messages are in the pool - * - */ - public int getLocalCount() { - synchronized (_inMessages) { - return _inMessages.size(); - } - } - - /** - * Determine how many remotely bound messages are in the pool. - * - */ - public int getRemoteCount() { - synchronized (_outMessages) { - return _outMessages.size(); - } - } - - public void dumpPoolInfo() { - StringBuffer buf = new StringBuffer(); - buf.append("\nDumping Client Message Pool. Local messages: ").append(getLocalCount()).append(" Remote messages: ").append(getRemoteCount()).append("\n"); - buf.append("Inbound messages\n"); - buf.append("----------------------------\n"); - synchronized (_inMessages) { - for (Iterator iter = _inMessages.iterator(); iter.hasNext();) { - ClientMessage msg = (ClientMessage)iter.next(); - buf.append(msg).append("\n\n"); - } - } - buf.append("Outbound messages\n"); - buf.append("----------------------------\n"); - synchronized (_outMessages) { - for (Iterator iter = _outMessages.iterator(); iter.hasNext();) { - ClientMessage msg = (ClientMessage)iter.next(); - buf.append(msg).append("\n\n"); - } - } - _log.debug(buf.toString()); + if ( (_context.clientManager().isLocal(msg.getDestination())) || + (_context.clientManager().isLocal(msg.getDestinationHash())) ) { + _log.debug("Adding message for local delivery"); + _context.clientManager().messageReceived(msg); + } else { + _log.debug("Adding message for remote delivery"); + _context.jobQueue().addJob(new OutboundClientMessageJob(_context, msg)); + } } } diff --git a/router/java/src/net/i2p/router/CommSystemFacade.java b/router/java/src/net/i2p/router/CommSystemFacade.java index 2f2eec573..d3342138f 100644 --- a/router/java/src/net/i2p/router/CommSystemFacade.java +++ b/router/java/src/net/i2p/router/CommSystemFacade.java @@ -11,20 +11,12 @@ package net.i2p.router; import java.util.HashSet; import java.util.Set; -import net.i2p.router.transport.CommSystemFacadeImpl; - /** * Manages the communication subsystem between peers, including connections, * listeners, transports, connection keys, etc. * */ public abstract class CommSystemFacade implements Service { - private static CommSystemFacade _instance = new CommSystemFacadeImpl(); - public static CommSystemFacade getInstance() { return _instance; } - - // getAddresses - // rotateAddress(address) - public abstract void processMessage(OutNetMessage msg); public String renderStatusHTML() { return ""; } diff --git a/router/java/src/net/i2p/router/GenerateStatusConsoleJob.java b/router/java/src/net/i2p/router/GenerateStatusConsoleJob.java deleted file mode 100644 index 8faa129c3..000000000 --- a/router/java/src/net/i2p/router/GenerateStatusConsoleJob.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.i2p.router; -/* - * 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.FileOutputStream; -import java.io.IOException; - -import net.i2p.util.Log; - -public class GenerateStatusConsoleJob extends JobImpl { - private final static Log _log = new Log(GenerateStatusConsoleJob.class); - - private final static long REGENERATE_DELAY_MS = 60*1000; // once per minute update the console - public final static String CONFIG_CONSOLE_LOCATION = "routerConsoleFile"; - public final static String DEFAULT_CONSOLE_LOCATION = "routerConsole.html"; - - public final static String PARAM_GENERATE_CONFIG_CONSOLE = "router.generateConsole"; - public final static boolean DEFAULT_GENERATE_CONFIG_CONSOLE = true; - - private boolean shouldGenerateConsole() { - String str = Router.getInstance().getConfigSetting(PARAM_GENERATE_CONFIG_CONSOLE); - if ( (str == null) || (str.trim().length() <= 0) ) - return DEFAULT_GENERATE_CONFIG_CONSOLE; - if (Boolean.TRUE.toString().equalsIgnoreCase(str)) - return true; - else - return false; - } - - public String getName() { return "Generate Status Console"; } - public void runJob() { - if (shouldGenerateConsole()) { - String consoleHTML = Router.getInstance().renderStatusHTML(); - writeConsole(consoleHTML); - } - requeue(REGENERATE_DELAY_MS); - } - - private void writeConsole(String html) { - String loc = Router.getInstance().getConfigSetting(CONFIG_CONSOLE_LOCATION); - if (loc == null) - loc = DEFAULT_CONSOLE_LOCATION; - - FileOutputStream fos = null; - try { - fos = new FileOutputStream(loc); - fos.write(html.getBytes()); - fos.flush(); - } catch (IOException ioe) { - _log.error("Error writing out the console", ioe); - } finally { - if (fos != null) try { fos.close(); } catch (IOException ioe) {} - } - } - -} diff --git a/router/java/src/net/i2p/router/InNetMessagePool.java b/router/java/src/net/i2p/router/InNetMessagePool.java index 30777cf9b..1889b0ae7 100644 --- a/router/java/src/net/i2p/router/InNetMessagePool.java +++ b/router/java/src/net/i2p/router/InNetMessagePool.java @@ -26,17 +26,18 @@ import net.i2p.util.Log; * */ public class InNetMessagePool { - private final static Log _log = new Log(InNetMessagePool.class); - private static InNetMessagePool _instance = new InNetMessagePool(); - public final static InNetMessagePool getInstance() { return _instance; } + private Log _log; + private RouterContext _context; private List _messages; private Map _handlerJobBuilders; - private InNetMessagePool() { + public InNetMessagePool(RouterContext context) { + _context = context; _messages = new ArrayList(); _handlerJobBuilders = new HashMap(); - StatManager.getInstance().createRateStat("inNetPool.dropped", "How often do we drop a message", "InNetPool", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); - StatManager.getInstance().createRateStat("inNetPool.duplicate", "How often do we receive a duplicate message", "InNetPool", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _log = _context.logManager().getLog(InNetMessagePool.class); + _context.statManager().createRateStat("inNetPool.dropped", "How often do we drop a message", "InNetPool", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _context.statManager().createRateStat("inNetPool.duplicate", "How often do we receive a duplicate message", "InNetPool", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); } public HandlerJobBuilder registerHandlerJobBuilder(int i2npMessageType, HandlerJobBuilder builder) { @@ -57,15 +58,15 @@ public class InNetMessagePool { */ public int add(InNetMessage msg) { Date exp = msg.getMessage().getMessageExpiration(); - boolean valid = MessageValidator.getInstance().validateMessage(msg.getMessage().getUniqueId(), exp.getTime()); + boolean valid = _context.messageValidator().validateMessage(msg.getMessage().getUniqueId(), exp.getTime()); if (!valid) { if (_log.shouldLog(Log.WARN)) _log.warn("Duplicate message received [" + msg.getMessage().getUniqueId() + " expiring on " + exp + "]: " + msg.getMessage().getClass().getName()); - StatManager.getInstance().addRateData("inNetPool.dropped", 1, 0); - StatManager.getInstance().addRateData("inNetPool.duplicate", 1, 0); - MessageHistory.getInstance().droppedOtherMessage(msg.getMessage()); - MessageHistory.getInstance().messageProcessingError(msg.getMessage().getUniqueId(), + _context.statManager().addRateData("inNetPool.dropped", 1, 0); + _context.statManager().addRateData("inNetPool.duplicate", 1, 0); + _context.messageHistory().droppedOtherMessage(msg.getMessage()); + _context.messageHistory().messageProcessingError(msg.getMessage().getUniqueId(), msg.getMessage().getClass().getName(), "Duplicate/expired"); return -1; @@ -87,14 +88,14 @@ public class InNetMessagePool { Job job = builder.createJob(msg.getMessage(), msg.getFromRouter(), msg.getFromRouterHash(), msg.getReplyBlock()); if (job != null) { - JobQueue.getInstance().addJob(job); + _context.jobQueue().addJob(job); synchronized (_messages) { size = _messages.size(); } } } - List origMessages = OutboundMessageRegistry.getInstance().getOriginalMessages(msg.getMessage()); + List origMessages = _context.messageRegistry().getOriginalMessages(msg.getMessage()); if (_log.shouldLog(Log.DEBUG)) _log.debug("Original messages for inbound message: " + origMessages.size()); if (origMessages.size() > 1) { @@ -112,7 +113,7 @@ public class InNetMessagePool { if (job != null) { job.setMessage(msg.getMessage()); - JobQueue.getInstance().addJob(job); + _context.jobQueue().addJob(job); } } @@ -120,24 +121,24 @@ public class InNetMessagePool { // not handled as a reply if (size == -1) { // was not handled via HandlerJobBuilder - MessageHistory.getInstance().droppedOtherMessage(msg.getMessage()); + _context.messageHistory().droppedOtherMessage(msg.getMessage()); if (_log.shouldLog(Log.ERROR)) _log.error("Message " + msg.getMessage() + " was not handled by a HandlerJobBuilder - DROPPING: " + msg, new Exception("DROPPED MESSAGE")); - StatManager.getInstance().addRateData("inNetPool.dropped", 1, 0); + _context.statManager().addRateData("inNetPool.dropped", 1, 0); } else { String mtype = msg.getMessage().getClass().getName(); - MessageHistory.getInstance().receiveMessage(mtype, msg.getMessage().getUniqueId(), - msg.getMessage().getMessageExpiration(), - msg.getFromRouterHash(), true); + _context.messageHistory().receiveMessage(mtype, msg.getMessage().getUniqueId(), + msg.getMessage().getMessageExpiration(), + msg.getFromRouterHash(), true); return size; } } String mtype = msg.getMessage().getClass().getName(); - MessageHistory.getInstance().receiveMessage(mtype, msg.getMessage().getUniqueId(), - msg.getMessage().getMessageExpiration(), - msg.getFromRouterHash(), true); + _context.messageHistory().receiveMessage(mtype, msg.getMessage().getUniqueId(), + msg.getMessage().getMessageExpiration(), + msg.getFromRouterHash(), true); return size; } @@ -174,19 +175,4 @@ public class InNetMessagePool { return _messages.size(); } } - - public void dumpPoolInfo() { - if (!_log.shouldLog(Log.DEBUG)) return; - - StringBuffer buf = new StringBuffer(); - buf.append("\nDumping Inbound Network Message Pool. Total # message: ").append(getCount()).append("\n"); - synchronized (_messages) { - for (Iterator iter = _messages.iterator(); iter.hasNext();) { - InNetMessage msg = (InNetMessage)iter.next(); - buf.append("Message ").append(msg.getMessage()).append("\n\n"); - } - } - _log.debug(buf.toString()); - } - } diff --git a/router/java/src/net/i2p/router/JobImpl.java b/router/java/src/net/i2p/router/JobImpl.java index b4b3bf29a..6cc9d5f27 100644 --- a/router/java/src/net/i2p/router/JobImpl.java +++ b/router/java/src/net/i2p/router/JobImpl.java @@ -13,40 +13,42 @@ import net.i2p.util.Clock; * Base implementation of a Job */ public abstract class JobImpl implements Job { + protected RouterContext _context; private JobTiming _timing; private static int _idSrc = 0; private int _id; private Exception _addedBy; private long _madeReadyOn; - public JobImpl() { - _timing = new JobTiming(); - _id = ++_idSrc; - _addedBy = null; - _madeReadyOn = 0; + public JobImpl(RouterContext context) { + _context = context; + _timing = new JobTiming(context); + _id = ++_idSrc; + _addedBy = null; + _madeReadyOn = 0; } public int getJobId() { return _id; } public JobTiming getTiming() { return _timing; } public String toString() { - StringBuffer buf = new StringBuffer(128); - buf.append(super.toString()); - buf.append(": Job ").append(_id).append(": ").append(getName()); - return buf.toString(); + StringBuffer buf = new StringBuffer(128); + buf.append(super.toString()); + buf.append(": Job ").append(_id).append(": ").append(getName()); + return buf.toString(); } void addedToQueue() { - _addedBy = new Exception(); + _addedBy = new Exception(); } public Exception getAddedBy() { return _addedBy; } public long getMadeReadyOn() { return _madeReadyOn; } - public void madeReady() { _madeReadyOn = Clock.getInstance().now(); } + public void madeReady() { _madeReadyOn = _context.clock().now(); } public void dropped() {} protected void requeue(long delayMs) { - getTiming().setStartAfter(Clock.getInstance().now() + delayMs); - JobQueue.getInstance().addJob(this); + getTiming().setStartAfter(_context.clock().now() + delayMs); + _context.jobQueue().addJob(this); } } diff --git a/router/java/src/net/i2p/router/JobQueue.java b/router/java/src/net/i2p/router/JobQueue.java index 23e5efdba..3a22d0ac8 100644 --- a/router/java/src/net/i2p/router/JobQueue.java +++ b/router/java/src/net/i2p/router/JobQueue.java @@ -11,7 +11,7 @@ package net.i2p.router; import java.util.Date; import java.util.HashMap; import java.util.Iterator; -import java.util.LinkedList; +import java.util.ArrayList; import java.util.TreeMap; import net.i2p.router.message.HandleSourceRouteReplyMessageJob; @@ -29,22 +29,21 @@ import net.i2p.util.Log; * */ public class JobQueue { - private final static Log _log = new Log(JobQueue.class); - private static JobQueue _instance = new JobQueue(); - public static JobQueue getInstance() { return _instance; } + private Log _log; + private RouterContext _context; /** Integer (runnerId) to JobQueueRunner for created runners */ - private static HashMap _queueRunners; + private HashMap _queueRunners; /** a counter to identify a job runner */ private volatile static int _runnerId = 0; /** list of jobs that are ready to run ASAP */ - private LinkedList _readyJobs; + private ArrayList _readyJobs; /** list of jobs that are scheduled for running in the future */ - private LinkedList _timedJobs; + private ArrayList _timedJobs; /** when true, don't run any new jobs or update any limits, etc */ private boolean _paused; /** job name to JobStat for that job */ - private static TreeMap _jobStats; + private TreeMap _jobStats; /** how many job queue runners can go concurrently */ private int _maxRunners; private QueuePumper _pumper; @@ -92,8 +91,6 @@ public class JobQueue { private final static String PROP_MAX_WAITING_JOBS = "router.maxWaitingJobs"; static { - StatManager.getInstance().createRateStat("jobQueue.readyJobs", "How many ready and waiting jobs there are?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); - StatManager.getInstance().createRateStat("jobQueue.droppedJobs", "How many jobs do we drop due to insane overload?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); } /** @@ -102,20 +99,31 @@ public class JobQueue { */ private Object _runnerLock = new Object(); - private JobQueue() { - _alive = true; - _readyJobs = new LinkedList(); - _timedJobs = new LinkedList(); - _queueRunners = new HashMap(); - _paused = false; - _jobStats = new TreeMap(); - _allowParallelOperation = false; - _pumper = new QueuePumper(); - I2PThread pumperThread = new I2PThread(_pumper); - pumperThread.setDaemon(true); - pumperThread.setName("QueuePumper"); - pumperThread.setPriority(I2PThread.MIN_PRIORITY); - pumperThread.start(); + public JobQueue(RouterContext context) { + _context = context; + _log = context.logManager().getLog(JobQueue.class); + _context.statManager().createRateStat("jobQueue.readyJobs", + "How many ready and waiting jobs there are?", + "JobQueue", + new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _context.statManager().createRateStat("jobQueue.droppedJobs", + "How many jobs do we drop due to insane overload?", + "JobQueue", + new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + + _alive = true; + _readyJobs = new ArrayList(); + _timedJobs = new ArrayList(); + _queueRunners = new HashMap(); + _paused = false; + _jobStats = new TreeMap(); + _allowParallelOperation = false; + _pumper = new QueuePumper(); + I2PThread pumperThread = new I2PThread(_pumper); + pumperThread.setDaemon(true); + pumperThread.setName("QueuePumper"); + pumperThread.setPriority(I2PThread.MIN_PRIORITY); + pumperThread.start(); } /** @@ -123,62 +131,63 @@ public class JobQueue { * */ public void addJob(Job job) { - if (job == null) return; - - if (job instanceof JobImpl) - ((JobImpl)job).addedToQueue(); - - boolean isReady = false; - long numReady = 0; - boolean alreadyExists = false; - synchronized (_readyJobs) { - if (_readyJobs.contains(job)) - alreadyExists = true; - numReady = _readyJobs.size(); - } - if (!alreadyExists) { - synchronized (_timedJobs) { - if (_timedJobs.contains(job)) - alreadyExists = true; - } - } - - StatManager.getInstance().addRateData("jobQueue.readyJobs", numReady, 0); - if (shouldDrop(job, numReady)) { - if (_log.shouldLog(Log.ERROR)) - _log.error("Dropping job due to overload! # ready jobs: " + numReady + ": job = " + job); - job.dropped(); - StatManager.getInstance().addRateData("jobQueue.droppedJobs", 1, 1); - awaken(1); - return; - } - - if (!alreadyExists) { - if (job.getTiming().getStartAfter() <= Clock.getInstance().now()) { - // don't skew us - its 'start after' its been queued, or later - job.getTiming().setStartAfter(Clock.getInstance().now()); - if (job instanceof JobImpl) - ((JobImpl)job).madeReady(); - synchronized (_readyJobs) { - _readyJobs.add(job); - isReady = true; - } - } else { - synchronized (_timedJobs) { - _timedJobs.add(job); - } - } - } else { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Not adding already enqueued job " + job.getName()); - } - - if (isReady) { - // wake up at most one runner - awaken(1); - } - - return; + if (job == null) return; + + if (job instanceof JobImpl) + ((JobImpl)job).addedToQueue(); + + boolean isReady = false; + long numReady = 0; + boolean alreadyExists = false; + synchronized (_readyJobs) { + if (_readyJobs.contains(job)) + alreadyExists = true; + numReady = _readyJobs.size(); + } + if (!alreadyExists) { + synchronized (_timedJobs) { + if (_timedJobs.contains(job)) + alreadyExists = true; + } + } + + _context.statManager().addRateData("jobQueue.readyJobs", numReady, 0); + if (shouldDrop(job, numReady)) { + if (_log.shouldLog(Log.ERROR)) + _log.error("Dropping job due to overload! # ready jobs: " + + numReady + ": job = " + job); + job.dropped(); + _context.statManager().addRateData("jobQueue.droppedJobs", 1, 1); + awaken(1); + return; + } + + if (!alreadyExists) { + if (job.getTiming().getStartAfter() <= _context.clock().now()) { + // don't skew us - its 'start after' its been queued, or later + job.getTiming().setStartAfter(_context.clock().now()); + if (job instanceof JobImpl) + ((JobImpl)job).madeReady(); + synchronized (_readyJobs) { + _readyJobs.add(job); + isReady = true; + } + } else { + synchronized (_timedJobs) { + _timedJobs.add(job); + } + } + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Not adding already enqueued job " + job.getName()); + } + + if (isReady) { + // wake up at most one runner + awaken(1); + } + + return; } /** @@ -189,35 +198,35 @@ public class JobQueue { * */ private boolean shouldDrop(Job job, long numReady) { - if (_maxWaitingJobs <= 0) return false; // dont ever drop jobs - if (!_allowParallelOperation) return false; // dont drop during startup [duh] - Class cls = job.getClass(); - if (numReady > _maxWaitingJobs) { - - // heavy cpu load, plus we're allowed to be unreliable with these two - // [but garlics can contain our payloads, so lets not drop them] - //if (cls == HandleGarlicMessageJob.class) - // return true; - if (cls == HandleSourceRouteReplyMessageJob.class) - return true; - - // lets not try to drop too many tunnel messages... - //if (cls == HandleTunnelMessageJob.class) - // return true; - - // we don't really *need* to answer DB lookup messages - if (cls == HandleDatabaseLookupMessageJob.class) - return true; - - // tunnels are a bitch, but its dropped() builds a pair of fake ones just in case - if (cls == RequestTunnelJob.class) - return true; - - // if we're already this loaded, dont take more tunnels - if (cls == HandleTunnelCreateMessageJob.class) - return true; - } - return false; + if (_maxWaitingJobs <= 0) return false; // dont ever drop jobs + if (!_allowParallelOperation) return false; // dont drop during startup [duh] + Class cls = job.getClass(); + if (numReady > _maxWaitingJobs) { + + // heavy cpu load, plus we're allowed to be unreliable with these two + // [but garlics can contain our payloads, so lets not drop them] + //if (cls == HandleGarlicMessageJob.class) + // return true; + if (cls == HandleSourceRouteReplyMessageJob.class) + return true; + + // lets not try to drop too many tunnel messages... + //if (cls == HandleTunnelMessageJob.class) + // return true; + + // we don't really *need* to answer DB lookup messages + if (cls == HandleDatabaseLookupMessageJob.class) + return true; + + // tunnels are a bitch, but its dropped() builds a pair of fake ones just in case + if (cls == RequestTunnelJob.class) + return true; + + // if we're already this loaded, dont take more tunnels + if (cls == HandleTunnelCreateMessageJob.class) + return true; + } + return false; } public void allowParallelOperation() { _allowParallelOperation = true; } @@ -229,32 +238,33 @@ public class JobQueue { * */ Job getNext() { - while (_alive) { - while (_paused) { - try { Thread.sleep(30); } catch (InterruptedException ie) {} - } - Job rv = null; - int ready = 0; - synchronized (_readyJobs) { - ready = _readyJobs.size(); - if (ready > 0) - rv = (Job)_readyJobs.remove(0); - } - if (rv != null) { - // we found one, but there may be more, so wake up enough - // other runners - awaken(ready-1); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Using a ready job after waking up " + (ready-1) + " others"); - return rv; - } - try { - synchronized (_runnerLock) { - _runnerLock.wait(1000); - } - } catch (InterruptedException ie) {} - } - return null; + while (_alive) { + while (_paused) { + try { Thread.sleep(30); } catch (InterruptedException ie) {} + } + Job rv = null; + int ready = 0; + synchronized (_readyJobs) { + ready = _readyJobs.size(); + if (ready > 0) + rv = (Job)_readyJobs.remove(0); + } + if (rv != null) { + // we found one, but there may be more, so wake up enough + // other runners + awaken(ready-1); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Using a ready job after waking up " + (ready-1) + " others"); + return rv; + } + + try { + synchronized (_runnerLock) { + _runnerLock.wait(1000); + } + } catch (InterruptedException ie) {} + } + return null; } /** @@ -263,31 +273,31 @@ public class JobQueue { * */ private int checkJobTimings() { - boolean newJobsReady = false; - long now = Clock.getInstance().now(); - LinkedList toAdd = new LinkedList(); - synchronized (_timedJobs) { - for (int i = 0; i < _timedJobs.size(); i++) { - Job j = (Job)_timedJobs.get(i); - // find jobs due to start before now - if (j.getTiming().getStartAfter() <= now) { - if (j instanceof JobImpl) - ((JobImpl)j).madeReady(); + boolean newJobsReady = false; + long now = _context.clock().now(); + ArrayList toAdd = new ArrayList(4); + synchronized (_timedJobs) { + for (int i = 0; i < _timedJobs.size(); i++) { + Job j = (Job)_timedJobs.get(i); + // find jobs due to start before now + if (j.getTiming().getStartAfter() <= now) { + if (j instanceof JobImpl) + ((JobImpl)j).madeReady(); - toAdd.add(j); - _timedJobs.remove(i); - i--; // so the index stays consistent - } - } - } - - int ready = 0; - synchronized (_readyJobs) { - _readyJobs.addAll(toAdd); - ready = _readyJobs.size(); - } - - return ready; + toAdd.add(j); + _timedJobs.remove(i); + i--; // so the index stays consistent + } + } + } + + int ready = 0; + synchronized (_readyJobs) { + _readyJobs.addAll(toAdd); + ready = _readyJobs.size(); + } + + return ready; } /** @@ -299,39 +309,40 @@ public class JobQueue { * */ public void runQueue(int numThreads) { - synchronized (_queueRunners) { - // we're still starting up [serially] and we've got at least one runner, - // so dont do anything - if ( (_queueRunners.size() > 0) && (!_allowParallelOperation) ) return; - - // we've already enabled parallel operation, so grow to however many are - // specified - if (_queueRunners.size() < numThreads) { - if (_log.shouldLog(Log.INFO)) - _log.info("Increasing the number of queue runners from " + _queueRunners.size() + " to " + numThreads); - for (int i = _queueRunners.size(); i < numThreads; i++) { - JobQueueRunner runner = new JobQueueRunner(i); - _queueRunners.put(new Integer(i), runner); - Thread t = new I2PThread(runner); - t.setName("JobQueue"+(_runnerId++)); - t.setDaemon(false); - t.start(); - } - } else if (_queueRunners.size() == numThreads) { - // noop - } else { // numThreads < # runners, so shrink - //for (int i = _queueRunners.size(); i > numThreads; i++) { - // QueueRunner runner = (QueueRunner)_queueRunners.get(new Integer(i)); - // runner.stopRunning(); - //} - } - } + synchronized (_queueRunners) { + // we're still starting up [serially] and we've got at least one runner, + // so dont do anything + if ( (_queueRunners.size() > 0) && (!_allowParallelOperation) ) return; + + // we've already enabled parallel operation, so grow to however many are + // specified + if (_queueRunners.size() < numThreads) { + if (_log.shouldLog(Log.INFO)) + _log.info("Increasing the number of queue runners from " + + _queueRunners.size() + " to " + numThreads); + for (int i = _queueRunners.size(); i < numThreads; i++) { + JobQueueRunner runner = new JobQueueRunner(_context, i); + _queueRunners.put(new Integer(i), runner); + Thread t = new I2PThread(runner); + t.setName("JobQueue"+(_runnerId++)); + t.setDaemon(false); + t.start(); + } + } else if (_queueRunners.size() == numThreads) { + // noop + } else { // numThreads < # runners, so shrink + //for (int i = _queueRunners.size(); i > numThreads; i++) { + // QueueRunner runner = (QueueRunner)_queueRunners.get(new Integer(i)); + // runner.stopRunning(); + //} + } + } } //public void pauseQueue() { _paused = true; } //public void unpauseQueue() { _paused = false; } void removeRunner(int id) { _queueRunners.remove(new Integer(id)); } - + /** * Notify a sufficient number of waiting runners, and if necessary, increase @@ -339,29 +350,29 @@ public class JobQueue { * */ private void awaken(int numMadeReady) { - // notify a sufficient number of waiting runners - for (int i = 0; i < numMadeReady; i++) { - synchronized (_runnerLock) { - _runnerLock.notify(); - } - } - - int numRunners = 0; - synchronized (_queueRunners) { - numRunners = _queueRunners.size(); - } - - if (numRunners > 1) { - if (numMadeReady > numRunners) { - if (numMadeReady < _maxRunners) { - _log.info("Too much job contention (" + numMadeReady + " ready and waiting, " + numRunners + " runners exist), adding " + numMadeReady + " new runners (with max " + _maxRunners + ")"); - runQueue(numMadeReady); - } else { - _log.info("Too much job contention (" + numMadeReady + " ready and waiting, " + numRunners + " runners exist), increasing to our max of " + _maxRunners + " runners"); - runQueue(_maxRunners); - } - } - } + // notify a sufficient number of waiting runners + for (int i = 0; i < numMadeReady; i++) { + synchronized (_runnerLock) { + _runnerLock.notify(); + } + } + + int numRunners = 0; + synchronized (_queueRunners) { + numRunners = _queueRunners.size(); + } + + if (numRunners > 1) { + if (numMadeReady > numRunners) { + if (numMadeReady < _maxRunners) { + _log.info("Too much job contention (" + numMadeReady + " ready and waiting, " + numRunners + " runners exist), adding " + numMadeReady + " new runners (with max " + _maxRunners + ")"); + runQueue(numMadeReady); + } else { + _log.info("Too much job contention (" + numMadeReady + " ready and waiting, " + numRunners + " runners exist), increasing to our max of " + _maxRunners + " runners"); + runQueue(_maxRunners); + } + } + } } /** @@ -371,47 +382,47 @@ public class JobQueue { * */ private final class QueuePumper implements Runnable, Clock.ClockUpdateListener { - private long _lastLimitUpdated; - public QueuePumper() { - _lastLimitUpdated = 0; - Clock.getInstance().addUpdateListener(this); - } - public void run() { - try { - while (_alive) { - while (_paused) { - try { Thread.sleep(1000); } catch (InterruptedException ie) {} - } + private long _lastLimitUpdated; + public QueuePumper() { + _lastLimitUpdated = 0; + _context.clock().addUpdateListener(this); + } + public void run() { + try { + while (_alive) { + while (_paused) { + try { Thread.sleep(1000); } catch (InterruptedException ie) {} + } + + // periodically update our max runners limit + long now = _context.clock().now(); + if (now > _lastLimitUpdated + MAX_LIMIT_UPDATE_DELAY) { + if (_log.shouldLog(Log.INFO)) + _log.info("Updating the limits"); + updateMaxLimit(); + updateTimingLimits(); + _lastLimitUpdated = now; + } - // periodically update our max runners limit - long now = Clock.getInstance().now(); - if (now > _lastLimitUpdated + MAX_LIMIT_UPDATE_DELAY) { - if (_log.shouldLog(Log.INFO)) - _log.info("Updating the limits"); - updateMaxLimit(); - updateTimingLimits(); - _lastLimitUpdated = now; - } + // turn timed jobs into ready jobs + int numMadeReady = checkJobTimings(); - // turn timed jobs into ready jobs - int numMadeReady = checkJobTimings(); + awaken(numMadeReady); + + try { Thread.sleep(500); } catch (InterruptedException ie) {} + } + } catch (Throwable t) { + _context.clock().removeUpdateListener(this); + if (_log.shouldLog(Log.ERROR)) + _log.error("wtf, pumper killed", t); + } + } + + public void offsetChanged(long delta) { + if (_lastLimitUpdated > 0) + _lastLimitUpdated += delta; + } - awaken(numMadeReady); - - try { Thread.sleep(500); } catch (InterruptedException ie) {} - } - } catch (Throwable t) { - Clock.getInstance().removeUpdateListener(this); - if (_log.shouldLog(Log.ERROR)) - _log.error("wtf, pumper killed", t); - } - } - - public void offsetChanged(long delta) { - if (_lastLimitUpdated > 0) - _lastLimitUpdated += delta; - } - } /** @@ -420,57 +431,52 @@ public class JobQueue { * a warning (and if its really excessive, kill the router) */ void updateStats(Job job, long doStart, long origStartAfter, long duration) { - String key = job.getName(); - long lag = doStart - origStartAfter; // how long were we ready and waiting? - MessageHistory hist = MessageHistory.getInstance(); - long uptime = Router.getInstance().getUptime(); + String key = job.getName(); + long lag = doStart - origStartAfter; // how long were we ready and waiting? + MessageHistory hist = _context.messageHistory(); + long uptime = _context.router().getUptime(); - synchronized (_jobStats) { - if (!_jobStats.containsKey(key)) - _jobStats.put(key, new JobStats(key)); - JobStats stats = (JobStats)_jobStats.get(key); + synchronized (_jobStats) { + if (!_jobStats.containsKey(key)) + _jobStats.put(key, new JobStats(key)); + JobStats stats = (JobStats)_jobStats.get(key); + + stats.jobRan(duration, lag); + } - stats.jobRan(duration, lag); - } + String dieMsg = null; - String dieMsg = null; - boolean dumpRunners = false; - - if (lag > _lagWarning) { - dieMsg = "Lag too long for job " + job.getName() + " [" + lag + "ms and a run time of " + duration + "ms]"; - dumpRunners = true; - } else if (duration > _runWarning) { - dieMsg = "Job run too long for job " + job.getName() + " [" + lag + "ms lag and run time of " + duration + "ms]"; - dumpRunners = true; - } + if (lag > _lagWarning) { + dieMsg = "Lag too long for job " + job.getName() + " [" + lag + "ms and a run time of " + duration + "ms]"; + } else if (duration > _runWarning) { + dieMsg = "Job run too long for job " + job.getName() + " [" + lag + "ms lag and run time of " + duration + "ms]"; + } - if (dieMsg != null) { - if (_log.shouldLog(Log.WARN)) - _log.warn(dieMsg); - if (hist != null) - hist.messageProcessingError(-1, JobQueue.class.getName(), dieMsg); - } - - if (dumpRunners) - dumpRunners(true); - - if ( (lag > _lagFatal) && (uptime > _warmupTime) ) { - // this is fscking bad - the network at this size shouldn't have this much real contention - // so we're going to DIE DIE DIE - if (_log.shouldLog(Log.WARN)) - _log.log(Log.WARN, "The router is either incredibly overloaded or (more likely) there's an error.", new Exception("ttttooooo mmmuuuccccchhhh llllaaagggg")); - //try { Thread.sleep(5000); } catch (InterruptedException ie) {} - //Router.getInstance().shutdown(); - return; - } - if ( (uptime > _warmupTime) && (duration > _runFatal) ) { - // slow CPUs can get hosed with ElGamal, but 10s is too much. - if (_log.shouldLog(Log.WARN)) - _log.log(Log.WARN, "The router is incredibly overloaded - either you have a 386, or (more likely) there's an error. ", new Exception("ttttooooo sssllloooowww")); - //try { Thread.sleep(5000); } catch (InterruptedException ie) {} - //Router.getInstance().shutdown(); - return; - } + if (dieMsg != null) { + if (_log.shouldLog(Log.WARN)) + _log.warn(dieMsg); + if (hist != null) + hist.messageProcessingError(-1, JobQueue.class.getName(), dieMsg); + } + + if ( (lag > _lagFatal) && (uptime > _warmupTime) ) { + // this is fscking bad - the network at this size shouldn't have this much real contention + // so we're going to DIE DIE DIE + if (_log.shouldLog(Log.WARN)) + _log.log(Log.WARN, "The router is either incredibly overloaded or (more likely) there's an error.", new Exception("ttttooooo mmmuuuccccchhhh llllaaagggg")); + //try { Thread.sleep(5000); } catch (InterruptedException ie) {} + //Router.getInstance().shutdown(); + return; + } + + if ( (uptime > _warmupTime) && (duration > _runFatal) ) { + // slow CPUs can get hosed with ElGamal, but 10s is too much. + if (_log.shouldLog(Log.WARN)) + _log.log(Log.WARN, "The router is incredibly overloaded - either you have a 386, or (more likely) there's an error. ", new Exception("ttttooooo sssllloooowww")); + //try { Thread.sleep(5000); } catch (InterruptedException ie) {} + //Router.getInstance().shutdown(); + return; + } } //// @@ -482,18 +488,18 @@ public class JobQueue { * */ private void updateMaxLimit() { - String str = Router.getInstance().getConfigSetting(PROP_MAX_RUNNERS); - if (str != null) { - try { - _maxRunners = Integer.parseInt(str); - return; - } catch (NumberFormatException nfe) { - _log.error("Invalid maximum job runners [" + str + "]"); - } - } - if (_log.shouldLog(Log.INFO)) - _log.info("Defaulting the maximum job runners to " + DEFAULT_MAX_RUNNERS); - _maxRunners = DEFAULT_MAX_RUNNERS; + String str = _context.router().getConfigSetting(PROP_MAX_RUNNERS); + if (str != null) { + try { + _maxRunners = Integer.parseInt(str); + return; + } catch (NumberFormatException nfe) { + _log.error("Invalid maximum job runners [" + str + "]"); + } + } + if (_log.shouldLog(Log.INFO)) + _log.info("Defaulting the maximum job runners to " + DEFAULT_MAX_RUNNERS); + _maxRunners = DEFAULT_MAX_RUNNERS; } /** @@ -502,87 +508,87 @@ public class JobQueue { * */ private void updateTimingLimits() { - String str = Router.getInstance().getConfigSetting(PROP_LAG_WARNING); - if (str != null) { - try { - _lagWarning = Integer.parseInt(str); - } catch (NumberFormatException nfe) { - _log.error("Invalid job lag warning [" + str + "]"); - _lagWarning = DEFAULT_LAG_WARNING; - } - } else { - _lagWarning = DEFAULT_LAG_WARNING; - } - if (_log.shouldLog(Log.INFO)) - _log.info("Setting the warning job lag time to " + _lagWarning + "ms"); - - str = Router.getInstance().getConfigSetting(PROP_LAG_FATAL); - if (str != null) { - try { - _lagFatal = Integer.parseInt(str); - } catch (NumberFormatException nfe) { - _log.error("Invalid job lag fatal [" + str + "]"); - _lagFatal = DEFAULT_LAG_FATAL; - } - } else { - _lagFatal = DEFAULT_LAG_FATAL; - } - if (_log.shouldLog(Log.INFO)) - _log.info("Setting the fatal job lag time to " + _lagFatal + "ms"); - - str = Router.getInstance().getConfigSetting(PROP_RUN_WARNING); - if (str != null) { - try { - _runWarning = Integer.parseInt(str); - } catch (NumberFormatException nfe) { - _log.error("Invalid job run warning [" + str + "]"); - _runWarning = DEFAULT_RUN_WARNING; - } - } else { - _runWarning = DEFAULT_RUN_WARNING; - } - if (_log.shouldLog(Log.INFO)) - _log.info("Setting the warning job run time to " + _runWarning + "ms"); - - str = Router.getInstance().getConfigSetting(PROP_RUN_FATAL); - if (str != null) { - try { - _runFatal = Integer.parseInt(str); - } catch (NumberFormatException nfe) { - _log.error("Invalid job run fatal [" + str + "]"); - _runFatal = DEFAULT_RUN_FATAL; - } - } else { - _runFatal = DEFAULT_RUN_FATAL; - } - if (_log.shouldLog(Log.INFO)) - _log.info("Setting the fatal job run time to " + _runFatal + "ms"); - - str = Router.getInstance().getConfigSetting(PROP_WARMUM_TIME); - if (str != null) { - try { - _warmupTime = Integer.parseInt(str); - } catch (NumberFormatException nfe) { - _log.error("Invalid warmup time [" + str + "]"); - _warmupTime = DEFAULT_WARMUP_TIME; - } - } else { - _warmupTime = DEFAULT_WARMUP_TIME; - } - - str = Router.getInstance().getConfigSetting(PROP_MAX_WAITING_JOBS); - if (str != null) { - try { - _maxWaitingJobs = Integer.parseInt(str); - } catch (NumberFormatException nfe) { - _log.error("Invalid max waiting jobs [" + str + "]"); - _maxWaitingJobs = DEFAULT_MAX_WAITING_JOBS; - } - } else { - _maxWaitingJobs = DEFAULT_MAX_WAITING_JOBS; - } - if (_log.shouldLog(Log.INFO)) - _log.info("Setting the max waiting jobs to " + _maxWaitingJobs); + String str = _context.router().getConfigSetting(PROP_LAG_WARNING); + if (str != null) { + try { + _lagWarning = Integer.parseInt(str); + } catch (NumberFormatException nfe) { + _log.error("Invalid job lag warning [" + str + "]"); + _lagWarning = DEFAULT_LAG_WARNING; + } + } else { + _lagWarning = DEFAULT_LAG_WARNING; + } + if (_log.shouldLog(Log.INFO)) + _log.info("Setting the warning job lag time to " + _lagWarning + "ms"); + + str = _context.router().getConfigSetting(PROP_LAG_FATAL); + if (str != null) { + try { + _lagFatal = Integer.parseInt(str); + } catch (NumberFormatException nfe) { + _log.error("Invalid job lag fatal [" + str + "]"); + _lagFatal = DEFAULT_LAG_FATAL; + } + } else { + _lagFatal = DEFAULT_LAG_FATAL; + } + if (_log.shouldLog(Log.INFO)) + _log.info("Setting the fatal job lag time to " + _lagFatal + "ms"); + + str = _context.router().getConfigSetting(PROP_RUN_WARNING); + if (str != null) { + try { + _runWarning = Integer.parseInt(str); + } catch (NumberFormatException nfe) { + _log.error("Invalid job run warning [" + str + "]"); + _runWarning = DEFAULT_RUN_WARNING; + } + } else { + _runWarning = DEFAULT_RUN_WARNING; + } + if (_log.shouldLog(Log.INFO)) + _log.info("Setting the warning job run time to " + _runWarning + "ms"); + + str = _context.router().getConfigSetting(PROP_RUN_FATAL); + if (str != null) { + try { + _runFatal = Integer.parseInt(str); + } catch (NumberFormatException nfe) { + _log.error("Invalid job run fatal [" + str + "]"); + _runFatal = DEFAULT_RUN_FATAL; + } + } else { + _runFatal = DEFAULT_RUN_FATAL; + } + if (_log.shouldLog(Log.INFO)) + _log.info("Setting the fatal job run time to " + _runFatal + "ms"); + + str = _context.router().getConfigSetting(PROP_WARMUM_TIME); + if (str != null) { + try { + _warmupTime = Integer.parseInt(str); + } catch (NumberFormatException nfe) { + _log.error("Invalid warmup time [" + str + "]"); + _warmupTime = DEFAULT_WARMUP_TIME; + } + } else { + _warmupTime = DEFAULT_WARMUP_TIME; + } + + str = _context.router().getConfigSetting(PROP_MAX_WAITING_JOBS); + if (str != null) { + try { + _maxWaitingJobs = Integer.parseInt(str); + } catch (NumberFormatException nfe) { + _log.error("Invalid max waiting jobs [" + str + "]"); + _maxWaitingJobs = DEFAULT_MAX_WAITING_JOBS; + } + } else { + _maxWaitingJobs = DEFAULT_MAX_WAITING_JOBS; + } + if (_log.shouldLog(Log.INFO)) + _log.info("Setting the max waiting jobs to " + _maxWaitingJobs); } //// @@ -590,159 +596,124 @@ public class JobQueue { //// public String renderStatusHTML() { - LinkedList readyJobs = new LinkedList(); - LinkedList timedJobs = new LinkedList(); - LinkedList activeJobs = new LinkedList(); - synchronized (_readyJobs) { readyJobs.addAll(_readyJobs); } - synchronized (_timedJobs) { timedJobs.addAll(_timedJobs); } - synchronized (_queueRunners) { - for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext();) { - JobQueueRunner runner = (JobQueueRunner)iter.next(); - Job job = runner.getCurrentJob(); - if (job != null) - activeJobs.add(job.getName()); - } - } - StringBuffer buf = new StringBuffer(); - buf.append("

JobQueue

"); - buf.append("# runners: "); - synchronized (_queueRunners) { - buf.append(_queueRunners.size()); - } - buf.append("
\n"); - buf.append("# active jobs: ").append(activeJobs.size()).append("
    \n"); - for (int i = 0; i < activeJobs.size(); i++) { - buf.append("
  1. ").append(activeJobs.get(i)).append("
  2. \n"); - } - buf.append("
\n"); - buf.append("# ready/waiting jobs: ").append(readyJobs.size()).append(" (lots of these mean there's likely a big problem)
    \n"); - for (int i = 0; i < readyJobs.size(); i++) { - buf.append("
  1. ").append(readyJobs.get(i)).append("
  2. \n"); - } - buf.append("
\n"); - - buf.append("# timed jobs: ").append(timedJobs.size()).append("
    \n"); - TreeMap ordered = new TreeMap(); - for (int i = 0; i < timedJobs.size(); i++) { - Job j = (Job)timedJobs.get(i); - ordered.put(new Long(j.getTiming().getStartAfter()), j); - } - for (Iterator iter = ordered.values().iterator(); iter.hasNext(); ) { - Job j = (Job)iter.next(); - buf.append("
  1. ").append(j.getName()).append(" @ ").append(new Date(j.getTiming().getStartAfter())).append("
  2. \n"); - } - buf.append("
\n"); - buf.append(getJobStats()); - return buf.toString(); + ArrayList readyJobs = null; + ArrayList timedJobs = null; + ArrayList activeJobs = new ArrayList(4); + synchronized (_readyJobs) { readyJobs = new ArrayList(_readyJobs); } + synchronized (_timedJobs) { timedJobs = new ArrayList(_timedJobs); } + synchronized (_queueRunners) { + for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext();) { + JobQueueRunner runner = (JobQueueRunner)iter.next(); + Job job = runner.getCurrentJob(); + if (job != null) + activeJobs.add(job.getName()); + } + } + StringBuffer buf = new StringBuffer(20*1024); + buf.append("

JobQueue

"); + buf.append("# runners: "); + synchronized (_queueRunners) { + buf.append(_queueRunners.size()); + } + buf.append("
\n"); + buf.append("# active jobs: ").append(activeJobs.size()).append("
    \n"); + for (int i = 0; i < activeJobs.size(); i++) { + buf.append("
  1. ").append(activeJobs.get(i)).append("
  2. \n"); + } + buf.append("
\n"); + buf.append("# ready/waiting jobs: ").append(readyJobs.size()).append(" (lots of these mean there's likely a big problem)
    \n"); + for (int i = 0; i < readyJobs.size(); i++) { + buf.append("
  1. ").append(readyJobs.get(i)).append("
  2. \n"); + } + buf.append("
\n"); + + buf.append("# timed jobs: ").append(timedJobs.size()).append("
    \n"); + TreeMap ordered = new TreeMap(); + for (int i = 0; i < timedJobs.size(); i++) { + Job j = (Job)timedJobs.get(i); + ordered.put(new Long(j.getTiming().getStartAfter()), j); + } + for (Iterator iter = ordered.values().iterator(); iter.hasNext(); ) { + Job j = (Job)iter.next(); + buf.append("
  1. ").append(j.getName()).append(" @ "); + buf.append(new Date(j.getTiming().getStartAfter())).append("
  2. \n"); + } + buf.append("
\n"); + buf.append(getJobStats()); + return buf.toString(); } /** render the HTML for the job stats */ private String getJobStats() { - StringBuffer buf = new StringBuffer(1024); - buf.append("\n"); - buf.append(""); - buf.append(""); - buf.append("\n"); - long totRuns = 0; - long totExecTime = 0; - long avgExecTime = 0; - long maxExecTime = -1; - long minExecTime = -1; - long totPendingTime = 0; - long avgPendingTime = 0; - long maxPendingTime = -1; - long minPendingTime = -1; - - TreeMap tstats = null; - synchronized (_jobStats) { - tstats = (TreeMap)_jobStats.clone(); - } + StringBuffer buf = new StringBuffer(16*1024); + buf.append("
JobRunsTimeAvgMaxMinPendingAvgMaxMin
\n"); + buf.append(""); + buf.append(""); + buf.append("\n"); + long totRuns = 0; + long totExecTime = 0; + long avgExecTime = 0; + long maxExecTime = -1; + long minExecTime = -1; + long totPendingTime = 0; + long avgPendingTime = 0; + long maxPendingTime = -1; + long minPendingTime = -1; - for (Iterator iter = tstats.values().iterator(); iter.hasNext(); ) { - JobStats stats = (JobStats)iter.next(); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append("\n"); - totRuns += stats.getRuns(); - totExecTime += stats.getTotalTime(); - if (stats.getMaxTime() > maxExecTime) - maxExecTime = stats.getMaxTime(); - if ( (minExecTime < 0) || (minExecTime > stats.getMinTime()) ) - minExecTime = stats.getMinTime(); - totPendingTime += stats.getTotalPendingTime(); - if (stats.getMaxPendingTime() > maxPendingTime) - maxPendingTime = stats.getMaxPendingTime(); - if ( (minPendingTime < 0) || (minPendingTime > stats.getMinPendingTime()) ) - minPendingTime = stats.getMinPendingTime(); - } + TreeMap tstats = null; + synchronized (_jobStats) { + tstats = (TreeMap)_jobStats.clone(); + } - if (totRuns != 0) { - if (totExecTime != 0) - avgExecTime = totExecTime / totRuns; - if (totPendingTime != 0) - avgPendingTime = totPendingTime / totRuns; - } + for (Iterator iter = tstats.values().iterator(); iter.hasNext(); ) { + JobStats stats = (JobStats)iter.next(); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append("\n"); + totRuns += stats.getRuns(); + totExecTime += stats.getTotalTime(); + if (stats.getMaxTime() > maxExecTime) + maxExecTime = stats.getMaxTime(); + if ( (minExecTime < 0) || (minExecTime > stats.getMinTime()) ) + minExecTime = stats.getMinTime(); + totPendingTime += stats.getTotalPendingTime(); + if (stats.getMaxPendingTime() > maxPendingTime) + maxPendingTime = stats.getMaxPendingTime(); + if ( (minPendingTime < 0) || (minPendingTime > stats.getMinPendingTime()) ) + minPendingTime = stats.getMinPendingTime(); + } + + if (totRuns != 0) { + if (totExecTime != 0) + avgExecTime = totExecTime / totRuns; + if (totPendingTime != 0) + avgPendingTime = totPendingTime / totRuns; + } + + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append(""); + buf.append("\n"); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append(""); - buf.append("\n"); - - buf.append("
JobRunsTimeAvgMaxMinPendingAvgMaxMin
").append(stats.getName()).append("").append(stats.getRuns()).append("").append(stats.getTotalTime()).append("").append(stats.getAvgTime()).append("").append(stats.getMaxTime()).append("").append(stats.getMinTime()).append("").append(stats.getTotalPendingTime()).append("").append(stats.getAvgPendingTime()).append("").append(stats.getMaxPendingTime()).append("").append(stats.getMinPendingTime()).append("
").append(stats.getName()).append("").append(stats.getRuns()).append("").append(stats.getTotalTime()).append("").append(stats.getAvgTime()).append("").append(stats.getMaxTime()).append("").append(stats.getMinTime()).append("").append(stats.getTotalPendingTime()).append("").append(stats.getAvgPendingTime()).append("").append(stats.getMaxPendingTime()).append("").append(stats.getMinPendingTime()).append("

").append("SUMMARY").append("").append(totRuns).append("").append(totExecTime).append("").append(avgExecTime).append("").append(maxExecTime).append("").append(minExecTime).append("").append(totPendingTime).append("").append(avgPendingTime).append("").append(maxPendingTime).append("").append(minPendingTime).append("

").append("SUMMARY").append("").append(totRuns).append("").append(totExecTime).append("").append(avgExecTime).append("").append(maxExecTime).append("").append(minExecTime).append("").append(totPendingTime).append("").append(avgPendingTime).append("").append(maxPendingTime).append("").append(minPendingTime).append("
\n"); - return buf.toString(); - } - - /** - * Log what each queue runner is doing at the moment - * - */ - void dumpRunners() { dumpRunners(false); } - /** if asError, dump the job runners in an error message, else as a debug message */ - void dumpRunners(boolean asError) { - if (!asError && (!_log.shouldLog(Log.DEBUG)) ) return; - if (asError && (!_log.shouldLog(Log.WARN)) ) return; - StringBuffer buf = new StringBuffer(1024); - buf.append("Queue runners:\n"); - synchronized (_queueRunners) { - for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext(); ) { - JobQueueRunner runner = (JobQueueRunner)iter.next(); - Job job = runner.getCurrentJob(); - int id = runner.getRunnerId(); - buf.append("* Runner ").append(id).append(": \t"); - if (job == null) - buf.append("no job\n"); - else - buf.append(job.getName()).append('\n'); - } - } - synchronized (_timedJobs) { - buf.append("** Timed jobs: \t").append(_timedJobs.size()).append('\n'); - } - synchronized (_readyJobs) { - buf.append("** Ready jobs: \t").append(_readyJobs.size()).append('\n'); - } - - if (asError) - _log.warn(buf.toString()); - else - _log.debug(buf.toString()); + buf.append("\n"); + return buf.toString(); } } diff --git a/router/java/src/net/i2p/router/JobQueueRunner.java b/router/java/src/net/i2p/router/JobQueueRunner.java index c59300149..17f7656df 100644 --- a/router/java/src/net/i2p/router/JobQueueRunner.java +++ b/router/java/src/net/i2p/router/JobQueueRunner.java @@ -6,103 +6,105 @@ import net.i2p.util.Log; /** a do run run run a do run run */ class JobQueueRunner implements Runnable { - private final static Log _log = new Log(JobQueueRunner.class); + private Log _log; + private RouterContext _context; private boolean _keepRunning; private int _id; private long _numJobs; private Job _currentJob; - static { - StatManager.getInstance().createRateStat("jobQueue.jobRun", "How long jobs take", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); - StatManager.getInstance().createRateStat("jobQueue.jobLag", "How long jobs have to wait before running", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); - StatManager.getInstance().createRateStat("jobQueue.jobWait", "How long does a job sat on the job queue?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); - StatManager.getInstance().createRateStat("jobQueue.jobRunnerInactive", "How long are runners inactive?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + public JobQueueRunner(RouterContext context, int id) { + _context = context; + _id = id; + _keepRunning = true; + _numJobs = 0; + _currentJob = null; + _log = _context.logManager().getLog(JobQueueRunner.class); + _context.statManager().createRateStat("jobQueue.jobRun", "How long jobs take", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _context.statManager().createRateStat("jobQueue.jobLag", "How long jobs have to wait before running", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _context.statManager().createRateStat("jobQueue.jobWait", "How long does a job sat on the job queue?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); + _context.statManager().createRateStat("jobQueue.jobRunnerInactive", "How long are runners inactive?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); } - public JobQueueRunner(int id) { - _id = id; - _keepRunning = true; - _numJobs = 0; - _currentJob = null; - } public Job getCurrentJob() { return _currentJob; } public int getRunnerId() { return _id; } public void stopRunning() { _keepRunning = false; } public void run() { - long lastActive = Clock.getInstance().now();; - while ( (_keepRunning) && (JobQueue.getInstance().isAlive()) ) { - try { - Job job = JobQueue.getInstance().getNext(); - if (job == null) continue; - long now = Clock.getInstance().now(); - - long enqueuedTime = 0; - if (job instanceof JobImpl) { - long when = ((JobImpl)job).getMadeReadyOn(); - if (when <= 0) { - _log.error("Job was not made ready?! " + job, new Exception("Not made ready?!")); - } else { - enqueuedTime = now - when; - } - } - - long betweenJobs = now - lastActive; - StatManager.getInstance().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs); - _currentJob = job; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName()); - long origStartAfter = job.getTiming().getStartAfter(); - long doStart = Clock.getInstance().now(); - job.getTiming().start(); - runCurrentJob(); - job.getTiming().end(); - long duration = job.getTiming().getActualEnd() - job.getTiming().getActualStart(); + long lastActive = _context.clock().now(); + while ( (_keepRunning) && (_context.jobQueue().isAlive()) ) { + try { + Job job = _context.jobQueue().getNext(); + if (job == null) continue; + long now = _context.clock().now(); - long beforeUpdate = Clock.getInstance().now(); - JobQueue.getInstance().updateStats(job, doStart, origStartAfter, duration); - long diff = Clock.getInstance().now() - beforeUpdate; - - StatManager.getInstance().addRateData("jobQueue.jobRun", duration, duration); - StatManager.getInstance().addRateData("jobQueue.jobLag", doStart - origStartAfter, 0); - StatManager.getInstance().addRateData("jobQueue.jobWait", enqueuedTime, enqueuedTime); - - if (diff > 100) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Updating statistics for the job took too long [" + diff + "ms]"); - } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Job duration " + duration + "ms for " + job.getName() + " with lag of " + (doStart-origStartAfter) + "ms"); - lastActive = Clock.getInstance().now(); - _currentJob = null; - } catch (Throwable t) { - if (_log.shouldLog(Log.CRIT)) - _log.log(Log.CRIT, "WTF, error running?", t); - } - } - if (_log.shouldLog(Log.CRIT)) - _log.log(Log.CRIT, "Queue runner " + _id + " exiting"); - JobQueue.getInstance().removeRunner(_id); + long enqueuedTime = 0; + if (job instanceof JobImpl) { + long when = ((JobImpl)job).getMadeReadyOn(); + if (when <= 0) { + _log.error("Job was not made ready?! " + job, + new Exception("Not made ready?!")); + } else { + enqueuedTime = now - when; + } + } + + long betweenJobs = now - lastActive; + _context.statManager().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs); + _currentJob = job; + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName()); + long origStartAfter = job.getTiming().getStartAfter(); + long doStart = _context.clock().now(); + job.getTiming().start(); + runCurrentJob(); + job.getTiming().end(); + long duration = job.getTiming().getActualEnd() - job.getTiming().getActualStart(); + long beforeUpdate = _context.clock().now(); + _context.jobQueue().updateStats(job, doStart, origStartAfter, duration); + long diff = _context.clock().now() - beforeUpdate; + + _context.statManager().addRateData("jobQueue.jobRun", duration, duration); + _context.statManager().addRateData("jobQueue.jobLag", doStart - origStartAfter, 0); + _context.statManager().addRateData("jobQueue.jobWait", enqueuedTime, enqueuedTime); + + if (diff > 100) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Updating statistics for the job took too long [" + diff + "ms]"); + } + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Job duration " + duration + "ms for " + job.getName() + + " with lag of " + (doStart-origStartAfter) + "ms"); + lastActive = _context.clock().now(); + _currentJob = null; + } catch (Throwable t) { + if (_log.shouldLog(Log.CRIT)) + _log.log(Log.CRIT, "WTF, error running?", t); + } + } + if (_log.shouldLog(Log.CRIT)) + _log.log(Log.CRIT, "Queue runner " + _id + " exiting"); + _context.jobQueue().removeRunner(_id); } private void runCurrentJob() { - try { - _currentJob.runJob(); - } catch (OutOfMemoryError oom) { - try { - if (_log.shouldLog(Log.CRIT)) - _log.log(Log.CRIT, "Router ran out of memory, shutting down", oom); - Router.getInstance().shutdown(); - } catch (Throwable t) { - System.err.println("***Router ran out of memory, shutting down hard"); - } - try { Thread.sleep(1000); } catch (InterruptedException ie) {} - System.exit(-1); - } catch (Throwable t) { - if (_log.shouldLog(Log.CRIT)) - _log.log(Log.CRIT, "Error processing job [" + _currentJob.getName() + "] on thread " + _id + ": " + t.getMessage(), t); - if (_log.shouldLog(Log.ERROR)) - _log.error("The above job was enqueued by: ", _currentJob.getAddedBy()); - JobQueue.getInstance().dumpRunners(true); - } + try { + _currentJob.runJob(); + } catch (OutOfMemoryError oom) { + try { + if (_log.shouldLog(Log.CRIT)) + _log.log(Log.CRIT, "Router ran out of memory, shutting down", oom); + _context.router().shutdown(); + } catch (Throwable t) { + System.err.println("***Router ran out of memory, shutting down hard"); + } + try { Thread.sleep(1000); } catch (InterruptedException ie) {} + System.exit(-1); + } catch (Throwable t) { + if (_log.shouldLog(Log.CRIT)) + _log.log(Log.CRIT, "Error processing job [" + _currentJob.getName() + + "] on thread " + _id + ": " + t.getMessage(), t); + if (_log.shouldLog(Log.ERROR)) + _log.error("The above job was enqueued by: ", _currentJob.getAddedBy()); + } } } diff --git a/router/java/src/net/i2p/router/JobTiming.java b/router/java/src/net/i2p/router/JobTiming.java index ab11e16f7..c623c38d9 100644 --- a/router/java/src/net/i2p/router/JobTiming.java +++ b/router/java/src/net/i2p/router/JobTiming.java @@ -1,14 +1,15 @@ package net.i2p.router; /* * 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 + * 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 net.i2p.util.Clock; + /** * Define the timing requirements and statistics for a particular job * @@ -17,12 +18,14 @@ public class JobTiming implements Clock.ClockUpdateListener { private long _start; private long _actualStart; private long _actualEnd; + private RouterContext _context; - public JobTiming() { - _start = Clock.getInstance().now(); - _actualStart = 0; - _actualEnd = 0; - Clock.getInstance().addUpdateListener(this); + public JobTiming(RouterContext context) { + _context = context; + _start = context.clock().now(); + _actualStart = 0; + _actualEnd = 0; + context.clock().addUpdateListener(this); } /** @@ -42,7 +45,7 @@ public class JobTiming implements Clock.ClockUpdateListener { * Notify the timing that the job began * */ - public void start() { _actualStart = Clock.getInstance().now(); } + public void start() { _actualStart = _context.clock().now(); } /** * # of milliseconds after the epoch the job actually ended * @@ -53,17 +56,17 @@ public class JobTiming implements Clock.ClockUpdateListener { * Notify the timing that the job finished * */ - public void end() { - _actualEnd = Clock.getInstance().now(); - Clock.getInstance().removeUpdateListener(this); + public void end() { + _actualEnd = _context.clock().now(); + _context.clock().removeUpdateListener(this); } public void offsetChanged(long delta) { - if (_start != 0) - _start += delta; - if (_actualStart != 0) - _actualStart += delta; - if (_actualEnd != 0) - _actualEnd += delta; + if (_start != 0) + _start += delta; + if (_actualStart != 0) + _actualStart += delta; + if (_actualEnd != 0) + _actualEnd += delta; } } diff --git a/router/java/src/net/i2p/router/KeyManager.java b/router/java/src/net/i2p/router/KeyManager.java index cf25aa21c..28444eaa5 100644 --- a/router/java/src/net/i2p/router/KeyManager.java +++ b/router/java/src/net/i2p/router/KeyManager.java @@ -32,9 +32,8 @@ import net.i2p.util.Log; * */ public class KeyManager { - private final static Log _log = new Log(KeyManager.class); - private static KeyManager _instance = new KeyManager(); - public static KeyManager getInstance() { return _instance; } + private Log _log; + private RouterContext _context; private PrivateKey _privateKey; private PublicKey _publicKey; private SigningPrivateKey _signingPrivateKey; @@ -49,13 +48,15 @@ public class KeyManager { private final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key"; private final static long DELAY = 30*1000; - private KeyManager() { - setPrivateKey(null); - setPublicKey(null); - setSigningPrivateKey(null); - setSigningPublicKey(null); - _leaseSetKeys = new HashMap(); - JobQueue.getInstance().addJob(new SynchronizeKeysJob()); + public KeyManager(RouterContext context) { + _context = context; + _log = _context.logManager().getLog(KeyManager.class); + setPrivateKey(null); + setPublicKey(null); + setSigningPrivateKey(null); + setSigningPublicKey(null); + _leaseSetKeys = new HashMap(); + _context.jobQueue().addJob(new SynchronizeKeysJob()); } /** Configure the router's private key */ @@ -72,119 +73,122 @@ public class KeyManager { public SigningPublicKey getSigningPublicKey() { return _signingPublicKey; } public void registerKeys(Destination dest, SigningPrivateKey leaseRevocationPrivateKey, PrivateKey endpointDecryptionKey) { - _log.info("Registering keys for destination " + dest.calculateHash().toBase64()); - LeaseSetKeys keys = new LeaseSetKeys(dest, leaseRevocationPrivateKey, endpointDecryptionKey); - synchronized (_leaseSetKeys) { - _leaseSetKeys.put(dest, keys); - } + _log.info("Registering keys for destination " + dest.calculateHash().toBase64()); + LeaseSetKeys keys = new LeaseSetKeys(dest, leaseRevocationPrivateKey, endpointDecryptionKey); + synchronized (_leaseSetKeys) { + _leaseSetKeys.put(dest, keys); + } } public LeaseSetKeys unregisterKeys(Destination dest) { - _log.info("Unregistering keys for destination " + dest.calculateHash().toBase64()); - synchronized (_leaseSetKeys) { - return (LeaseSetKeys)_leaseSetKeys.remove(dest); - } + _log.info("Unregistering keys for destination " + dest.calculateHash().toBase64()); + synchronized (_leaseSetKeys) { + return (LeaseSetKeys)_leaseSetKeys.remove(dest); + } } public LeaseSetKeys getKeys(Destination dest) { - synchronized (_leaseSetKeys) { - return (LeaseSetKeys)_leaseSetKeys.get(dest); - } + synchronized (_leaseSetKeys) { + return (LeaseSetKeys)_leaseSetKeys.get(dest); + } } public Set getAllKeys() { - HashSet keys = new HashSet(); - synchronized (_leaseSetKeys) { - keys.addAll(_leaseSetKeys.values()); - } - return keys; + HashSet keys = new HashSet(); + synchronized (_leaseSetKeys) { + keys.addAll(_leaseSetKeys.values()); + } + return keys; } private class SynchronizeKeysJob extends JobImpl { - public void runJob() { - String keyDir = Router.getInstance().getConfigSetting(PROP_KEYDIR); - if (keyDir == null) - keyDir = DEFAULT_KEYDIR; - File dir = new File(keyDir); - if (!dir.exists()) - dir.mkdirs(); - if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) - syncKeys(dir); - - getTiming().setStartAfter(Clock.getInstance().now()+DELAY); - JobQueue.getInstance().addJob(this); - } - - private void syncKeys(File keyDir) { - syncPrivateKey(keyDir); - syncPublicKey(keyDir); - syncSigningKey(keyDir); - syncVerificationKey(keyDir); - } - - private void syncPrivateKey(File keyDir) { - File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_ENC); - boolean exists = (_privateKey != null); - if (!exists) - _privateKey = new PrivateKey(); - _privateKey = (PrivateKey)syncKey(keyFile, _privateKey, exists); - } - private void syncPublicKey(File keyDir) { - File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_ENC); - boolean exists = (_publicKey != null); - if (!exists) - _publicKey = new PublicKey(); - _publicKey = (PublicKey)syncKey(keyFile, _publicKey, exists); - } - - private void syncSigningKey(File keyDir) { - File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_SIGNING); - boolean exists = (_signingPrivateKey != null); - if (!exists) - _signingPrivateKey = new SigningPrivateKey(); - _signingPrivateKey = (SigningPrivateKey)syncKey(keyFile, _signingPrivateKey, exists); - } - private void syncVerificationKey(File keyDir) { - File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_SIGNING); - boolean exists = (_signingPublicKey != null); - if (!exists) - _signingPublicKey = new SigningPublicKey(); - _signingPublicKey = (SigningPublicKey)syncKey(keyFile, _signingPublicKey, exists); - } - - private DataStructure syncKey(File keyFile, DataStructure structure, boolean exists) { - FileOutputStream out = null; - FileInputStream in = null; - try { - if (exists) { - out = new FileOutputStream(keyFile); - structure.writeBytes(out); - return structure; - } else { - if (keyFile.exists()) { - in = new FileInputStream(keyFile); - structure.readBytes(in); - return structure; - } else { - // we don't have it, and its not on disk. oh well. - return null; - } - } - } catch (IOException ioe) { - _log.error("Error syncing the structure to " + keyFile.getAbsolutePath(), ioe); - } catch (DataFormatException dfe) { - _log.error("Error syncing the structure with " + keyFile.getAbsolutePath(), dfe); - } finally { - if (out != null) try { out.close(); } catch (IOException ioe) {} - if (in != null) try { in.close(); } catch (IOException ioe) {} - } - - if (exists) - return structure; - else - return null; - } - - public String getName() { return "Synchronize Keys to Disk"; } + public SynchronizeKeysJob() { + super(KeyManager.this._context); + } + public void runJob() { + String keyDir = KeyManager.this._context.router().getConfigSetting(PROP_KEYDIR); + if (keyDir == null) + keyDir = DEFAULT_KEYDIR; + File dir = new File(keyDir); + if (!dir.exists()) + dir.mkdirs(); + if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) + syncKeys(dir); + + getTiming().setStartAfter(KeyManager.this._context.clock().now()+DELAY); + KeyManager.this._context.jobQueue().addJob(this); + } + + private void syncKeys(File keyDir) { + syncPrivateKey(keyDir); + syncPublicKey(keyDir); + syncSigningKey(keyDir); + syncVerificationKey(keyDir); + } + + private void syncPrivateKey(File keyDir) { + File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_ENC); + boolean exists = (_privateKey != null); + if (!exists) + _privateKey = new PrivateKey(); + _privateKey = (PrivateKey)syncKey(keyFile, _privateKey, exists); + } + private void syncPublicKey(File keyDir) { + File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_ENC); + boolean exists = (_publicKey != null); + if (!exists) + _publicKey = new PublicKey(); + _publicKey = (PublicKey)syncKey(keyFile, _publicKey, exists); + } + + private void syncSigningKey(File keyDir) { + File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_SIGNING); + boolean exists = (_signingPrivateKey != null); + if (!exists) + _signingPrivateKey = new SigningPrivateKey(); + _signingPrivateKey = (SigningPrivateKey)syncKey(keyFile, _signingPrivateKey, exists); + } + private void syncVerificationKey(File keyDir) { + File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_SIGNING); + boolean exists = (_signingPublicKey != null); + if (!exists) + _signingPublicKey = new SigningPublicKey(); + _signingPublicKey = (SigningPublicKey)syncKey(keyFile, _signingPublicKey, exists); + } + + private DataStructure syncKey(File keyFile, DataStructure structure, boolean exists) { + FileOutputStream out = null; + FileInputStream in = null; + try { + if (exists) { + out = new FileOutputStream(keyFile); + structure.writeBytes(out); + return structure; + } else { + if (keyFile.exists()) { + in = new FileInputStream(keyFile); + structure.readBytes(in); + return structure; + } else { + // we don't have it, and its not on disk. oh well. + return null; + } + } + } catch (IOException ioe) { + _log.error("Error syncing the structure to " + keyFile.getAbsolutePath(), ioe); + } catch (DataFormatException dfe) { + _log.error("Error syncing the structure with " + keyFile.getAbsolutePath(), dfe); + } finally { + if (out != null) try { out.close(); } catch (IOException ioe) {} + if (in != null) try { in.close(); } catch (IOException ioe) {} + } + + if (exists) + return structure; + else + return null; + } + + public String getName() { return "Synchronize Keys to Disk"; } } } diff --git a/router/java/src/net/i2p/router/MessageHistory.java b/router/java/src/net/i2p/router/MessageHistory.java index fde358b70..c2cf7edb5 100644 --- a/router/java/src/net/i2p/router/MessageHistory.java +++ b/router/java/src/net/i2p/router/MessageHistory.java @@ -23,13 +23,16 @@ import net.i2p.util.Log; * */ public class MessageHistory { - private final static Log _log = new Log(MessageHistory.class); - private static MessageHistory _instance; + private Log _log; + private RouterContext _context; private List _unwrittenEntries; // list of raw entries (strings) yet to be written private String _historyFile; // where to write private String _localIdent; // placed in each entry to uniquely identify the local router private boolean _doLog; // true == we want to log private boolean _doPause; // true == briefly stop writing data to the log (used while submitting it) + private ReinitializeJob _reinitializeJob; + private WriteJob _writeJob; + private SubmitMessageHistoryJob _submitMessageHistoryJob; private final static byte[] NL = System.getProperty("line.separator").getBytes(); private final static int FLUSH_SIZE = 1000; // write out at least once every 1000 entries @@ -41,21 +44,12 @@ public class MessageHistory { public final static String PROP_MESSAGE_HISTORY_FILENAME = "router.historyFilename"; public final static String DEFAULT_MESSAGE_HISTORY_FILENAME = "messageHistory.txt"; - public final static MessageHistory getInstance() { - if (_instance == null) - initialize(); - return _instance; - } - private final static void setInstance(MessageHistory hist) { - if (_instance != null) { - synchronized (_instance._unwrittenEntries) { - for (Iterator iter = _instance._unwrittenEntries.iterator(); iter.hasNext(); ) { - hist.addEntry((String)iter.next()); - } - _instance._unwrittenEntries.clear(); - } - } - _instance = hist; + public MessageHistory(RouterContext context) { + _context = context; + _reinitializeJob = new ReinitializeJob(); + _writeJob = new WriteJob(); + _submitMessageHistoryJob = new SubmitMessageHistoryJob(_context); + initialize(true); } void setDoLog(boolean log) { _doLog = log; } @@ -65,19 +59,19 @@ public class MessageHistory { String getFilename() { return _historyFile; } private void updateSettings() { - String keepHistory = Router.getInstance().getConfigSetting(PROP_KEEP_MESSAGE_HISTORY); - if (keepHistory != null) { - _doLog = Boolean.TRUE.toString().equalsIgnoreCase(keepHistory); - } else { - _doLog = DEFAULT_KEEP_MESSAGE_HISTORY; - } - - String filename = null; - if (_doLog) { - filename = Router.getInstance().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME); - if ( (filename == null) || (filename.trim().length() <= 0) ) - filename = DEFAULT_MESSAGE_HISTORY_FILENAME; - } + String keepHistory = _context.router().getConfigSetting(PROP_KEEP_MESSAGE_HISTORY); + if (keepHistory != null) { + _doLog = Boolean.TRUE.toString().equalsIgnoreCase(keepHistory); + } else { + _doLog = DEFAULT_KEEP_MESSAGE_HISTORY; + } + + String filename = null; + if (_doLog) { + filename = _context.router().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME); + if ( (filename == null) || (filename.trim().length() <= 0) ) + filename = DEFAULT_MESSAGE_HISTORY_FILENAME; + } } /** @@ -85,55 +79,38 @@ public class MessageHistory { * Call this whenever the router identity changes. * */ - public static void initialize() { - initialize(false); + public void initialize(boolean forceReinitialize) { + if (!forceReinitialize) return; + + if (_context.router().getRouterInfo() == null) { + _reinitializeJob.getTiming().setStartAfter(_context.clock().now()+5000); + _context.jobQueue().addJob(_reinitializeJob); + } else { + String filename = null; + filename = _context.router().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME); + if ( (filename == null) || (filename.trim().length() <= 0) ) + filename = DEFAULT_MESSAGE_HISTORY_FILENAME; + + _doLog = DEFAULT_KEEP_MESSAGE_HISTORY; + _historyFile = filename; + _localIdent = getName(_context.routerHash()); + _unwrittenEntries = new LinkedList(); + updateSettings(); + addEntry(getPrefix() + "** Router initialized (started up or changed identities)"); + _context.jobQueue().addJob(_writeJob); + _submitMessageHistoryJob.getTiming().setStartAfter(_context.clock().now() + 2*60*1000); + _context.jobQueue().addJob(_submitMessageHistoryJob); + } } - public static void initialize(boolean forceReinitialize) { - if ( (!forceReinitialize) && (_instance != null) ) return; - - if (Router.getInstance().getRouterInfo() == null) { - ReinitializeJob j = ReinitializeJob.getInstance(); - j.getTiming().setStartAfter(Clock.getInstance().now()+5000); - JobQueue.getInstance().addJob(j); - } else { - String filename = null; - filename = Router.getInstance().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME); - if ( (filename == null) || (filename.trim().length() <= 0) ) - filename = DEFAULT_MESSAGE_HISTORY_FILENAME; - MessageHistory hist = new MessageHistory(Router.getInstance().getRouterInfo().getIdentity().getHash(), filename); - setInstance(hist); - hist.updateSettings(); - getInstance().addEntry(getInstance().getPrefix() + "** Router initialized (started up or changed identities)"); - JobQueue.getInstance().addJob(new WriteJob()); - SubmitMessageHistoryJob histJob = new SubmitMessageHistoryJob(); - histJob.getTiming().setStartAfter(Clock.getInstance().now() + 2*60*1000); - JobQueue.getInstance().addJob(histJob); - } - } - - private static final class ReinitializeJob extends JobImpl { - private final static ReinitializeJob _jobInstance = new ReinitializeJob(); - public final static ReinitializeJob getInstance() { return _jobInstance; } - private ReinitializeJob() { - super(); - } - public void runJob() { - MessageHistory.initialize(); - } - public String getName() { return "Reinitialize message history"; } - } - - /** - * Create a component to monitor the message history of the router. - * - * @param localIdent Hash of local identity - * @param filename file to log trace info to - */ - private MessageHistory(Hash localIdent, String filename) { - _doLog = DEFAULT_KEEP_MESSAGE_HISTORY; - _historyFile = filename; - _localIdent = getName(localIdent); - _unwrittenEntries = new LinkedList(); + + private final class ReinitializeJob extends JobImpl { + private ReinitializeJob() { + super(MessageHistory.this._context); + } + public void runJob() { + initialize(true); + } + public String getName() { return "Reinitialize message history"; } } /** @@ -151,20 +128,20 @@ public class MessageHistory { * @param replyThrough the gateway of the tunnel that the sourceRoutePeer will be sending to */ public void requestTunnelCreate(TunnelId createTunnel, TunnelId outTunnel, Hash peerRequested, Hash nextPeer, Hash sourceRoutePeer, TunnelId replyTunnel, Hash replyThrough) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("request [").append(getName(peerRequested)).append("] to create tunnel ["); - buf.append(createTunnel.getTunnelId()).append("] "); - if (nextPeer != null) - buf.append("(next [").append(getName(nextPeer)).append("]) "); - if (outTunnel != null) - buf.append("via [").append(outTunnel.getTunnelId()).append("] "); - if (sourceRoutePeer != null) - buf.append("with replies routed through [").append(getName(sourceRoutePeer)).append("] "); - if ( (replyTunnel != null) && (replyThrough != null) ) - buf.append("who forwards it through [").append(replyTunnel.getTunnelId()).append("] on [").append(getName(replyThrough)).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("request [").append(getName(peerRequested)).append("] to create tunnel ["); + buf.append(createTunnel.getTunnelId()).append("] "); + if (nextPeer != null) + buf.append("(next [").append(getName(nextPeer)).append("]) "); + if (outTunnel != null) + buf.append("via [").append(outTunnel.getTunnelId()).append("] "); + if (sourceRoutePeer != null) + buf.append("with replies routed through [").append(getName(sourceRoutePeer)).append("] "); + if ( (replyTunnel != null) && (replyThrough != null) ) + buf.append("who forwards it through [").append(replyTunnel.getTunnelId()).append("] on [").append(getName(replyThrough)).append("]"); + addEntry(buf.toString()); } /** @@ -178,14 +155,14 @@ public class MessageHistory { * @param sourceRoutePeer peer through whom we should send our garlic routed ok through */ public void receiveTunnelCreate(TunnelId createTunnel, Hash nextPeer, Date expire, boolean ok, Hash sourceRoutePeer) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("receive tunnel create [").append(createTunnel.getTunnelId()).append("] "); - if (nextPeer != null) - buf.append("(next [").append(getName(nextPeer)).append("]) "); - buf.append("ok? ").append(ok).append(" expiring on [").append(getTime(expire)).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("receive tunnel create [").append(createTunnel.getTunnelId()).append("] "); + if (nextPeer != null) + buf.append("(next [").append(getName(nextPeer)).append("]) "); + buf.append("ok? ").append(ok).append(" expiring on [").append(getTime(expire)).append("]"); + addEntry(buf.toString()); } /** @@ -195,22 +172,22 @@ public class MessageHistory { * @param tunnel tunnel joined */ public void tunnelJoined(String state, TunnelInfo tunnel) { - if (!_doLog) return; - if (tunnel == null) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("joining tunnel [").append(tunnel.getTunnelId().getTunnelId()).append("] as [").append(state).append("] "); - buf.append(" (next: "); - TunnelInfo cur = tunnel; - while (cur.getNextHopInfo() != null) { - buf.append('[').append(getName(cur.getNextHopInfo().getThisHop())); - buf.append("], "); - cur = cur.getNextHopInfo(); - } - if (cur.getNextHop() != null) - buf.append('[').append(getName(cur.getNextHop())).append(']'); - buf.append(") expiring on [").append(getTime(new Date(tunnel.getSettings().getExpiration()))).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + if (tunnel == null) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("joining tunnel [").append(tunnel.getTunnelId().getTunnelId()).append("] as [").append(state).append("] "); + buf.append(" (next: "); + TunnelInfo cur = tunnel; + while (cur.getNextHopInfo() != null) { + buf.append('[').append(getName(cur.getNextHopInfo().getThisHop())); + buf.append("], "); + cur = cur.getNextHopInfo(); + } + if (cur.getNextHop() != null) + buf.append('[').append(getName(cur.getNextHop())).append(']'); + buf.append(") expiring on [").append(getTime(new Date(tunnel.getSettings().getExpiration()))).append("]"); + addEntry(buf.toString()); } /** @@ -219,12 +196,12 @@ public class MessageHistory { * @param tunnel tunnel failed */ public void tunnelFailed(TunnelId tunnel) { - if (!_doLog) return; - if (tunnel == null) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("failing tunnel [").append(tunnel.getTunnelId()).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + if (tunnel == null) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("failing tunnel [").append(tunnel.getTunnelId()).append("]"); + addEntry(buf.toString()); } /** @@ -235,24 +212,24 @@ public class MessageHistory { * @param timeToTest milliseconds to verify the tunnel */ public void tunnelValid(TunnelInfo tunnel, long timeToTest) { - if (!_doLog) return; - if (tunnel == null) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("tunnel ").append(tunnel.getTunnelId().getTunnelId()).append(" tested ok after ").append(timeToTest).append("ms (containing "); - TunnelInfo cur = tunnel; - while (cur != null) { - buf.append('[').append(getName(cur.getThisHop())).append("], "); - if (cur.getNextHopInfo() != null) { - cur = cur.getNextHopInfo(); - } else { - if (cur.getNextHop() != null) - buf.append('[').append(getName(cur.getNextHop())).append(']'); - cur = null; - } - } - buf.append(')'); - addEntry(buf.toString()); + if (!_doLog) return; + if (tunnel == null) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("tunnel ").append(tunnel.getTunnelId().getTunnelId()).append(" tested ok after ").append(timeToTest).append("ms (containing "); + TunnelInfo cur = tunnel; + while (cur != null) { + buf.append('[').append(getName(cur.getThisHop())).append("], "); + if (cur.getNextHopInfo() != null) { + cur = cur.getNextHopInfo(); + } else { + if (cur.getNextHop() != null) + buf.append('[').append(getName(cur.getNextHop())).append(']'); + cur = null; + } + } + buf.append(')'); + addEntry(buf.toString()); } /** @@ -260,15 +237,15 @@ public class MessageHistory { * */ public void tunnelRejected(Hash peer, TunnelId tunnel, Hash replyThrough, String reason) { - if (!_doLog) return; - if ( (tunnel == null) || (peer == null) ) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("tunnel [").append(tunnel.getTunnelId()).append("] was rejected by ["); - buf.append(getName(peer)).append("] for [").append(reason).append("]"); - if (replyThrough != null) - buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + if ( (tunnel == null) || (peer == null) ) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("tunnel [").append(tunnel.getTunnelId()).append("] was rejected by ["); + buf.append(getName(peer)).append("] for [").append(reason).append("]"); + if (replyThrough != null) + buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]"); + addEntry(buf.toString()); } /** @@ -277,15 +254,15 @@ public class MessageHistory { * */ public void tunnelRequestTimedOut(Hash peer, TunnelId tunnel, Hash replyThrough) { - if (!_doLog) return; - if ( (tunnel == null) || (peer == null) ) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("tunnel [").append(tunnel.getTunnelId()).append("] timed out on ["); - buf.append(getName(peer)).append("]"); - if (replyThrough != null) - buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + if ( (tunnel == null) || (peer == null) ) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("tunnel [").append(tunnel.getTunnelId()).append("] timed out on ["); + buf.append(getName(peer)).append("]"); + if (replyThrough != null) + buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]"); + addEntry(buf.toString()); } /** @@ -296,24 +273,24 @@ public class MessageHistory { * @param from peer that sent us this message (if known) */ public void droppedTunnelMessage(TunnelId id, Hash from) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("dropped message for unknown tunnel [").append(id.getTunnelId()).append("] from [").append(getName(from)).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("dropped message for unknown tunnel [").append(id.getTunnelId()).append("] from [").append(getName(from)).append("]"); + addEntry(buf.toString()); } /** * We received another message we weren't waiting for and don't know how to handle */ public void droppedOtherMessage(I2NPMessage message) { - if (!_doLog) return; - if (message == null) return; - StringBuffer buf = new StringBuffer(512); - buf.append(getPrefix()); - buf.append("dropped [").append(message.getClass().getName()).append("] ").append(message.getUniqueId()); - buf.append(" [").append(message.toString()).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + if (message == null) return; + StringBuffer buf = new StringBuffer(512); + buf.append(getPrefix()); + buf.append("dropped [").append(message.getClass().getName()).append("] ").append(message.getUniqueId()); + buf.append(" [").append(message.toString()).append("]"); + addEntry(buf.toString()); } /** @@ -322,16 +299,16 @@ public class MessageHistory { * @param sentMessage message sent that didn't receive a reply */ public void replyTimedOut(OutNetMessage sentMessage) { - if (!_doLog) return; - if (sentMessage == null) return; - StringBuffer buf = new StringBuffer(512); - buf.append(getPrefix()); - buf.append("timed out waiting for a reply to [").append(sentMessage.getMessage().getClass().getName()); - buf.append("] [").append(sentMessage.getMessage().getUniqueId()).append("] expiring on ["); - if (sentMessage != null) - buf.append(getTime(new Date(sentMessage.getReplySelector().getExpiration()))); - buf.append("] ").append(sentMessage.getReplySelector().toString()); - addEntry(buf.toString()); + if (!_doLog) return; + if (sentMessage == null) return; + StringBuffer buf = new StringBuffer(512); + buf.append(getPrefix()); + buf.append("timed out waiting for a reply to [").append(sentMessage.getMessage().getClass().getName()); + buf.append("] [").append(sentMessage.getMessage().getUniqueId()).append("] expiring on ["); + if (sentMessage != null) + buf.append(getTime(new Date(sentMessage.getReplySelector().getExpiration()))); + buf.append("] ").append(sentMessage.getReplySelector().toString()); + addEntry(buf.toString()); } /** @@ -342,11 +319,11 @@ public class MessageHistory { * @param error error message related to the processing of the message */ public void messageProcessingError(long messageId, String messageType, String error) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("Error processing [").append(messageType).append("] [").append(messageId).append("] failed with [").append(error).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("Error processing [").append(messageType).append("] [").append(messageId).append("] failed with [").append(error).append("]"); + addEntry(buf.toString()); } /** @@ -360,17 +337,17 @@ public class MessageHistory { * @param sentOk whether the message was sent successfully */ public void sendMessage(String messageType, long messageId, Date expiration, Hash peer, boolean sentOk) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("send [").append(messageType).append("] message [").append(messageId).append("] "); - buf.append("to [").append(getName(peer)).append("] "); - buf.append("expiring on [").append(getTime(expiration)).append("] "); - if (sentOk) - buf.append("successfully"); - else - buf.append("failed"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("send [").append(messageType).append("] message [").append(messageId).append("] "); + buf.append("to [").append(getName(peer)).append("] "); + buf.append("expiring on [").append(getTime(expiration)).append("] "); + if (sentOk) + buf.append("successfully"); + else + buf.append("failed"); + addEntry(buf.toString()); } /** @@ -385,20 +362,20 @@ public class MessageHistory { * */ public void receiveMessage(String messageType, long messageId, Date expiration, Hash from, boolean isValid) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("receive [").append(messageType).append("] with id [").append(messageId).append("] "); - if (from != null) - buf.append("from [").append(getName(from)).append("] "); - buf.append("expiring on [").append(getTime(expiration)).append("] valid? ").append(isValid); - addEntry(buf.toString()); - if (messageType.equals("net.i2p.data.i2np.TunnelMessage")) { - //_log.warn("ReceiveMessage tunnel message ["+messageId+"]", new Exception("Receive tunnel")); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("receive [").append(messageType).append("] with id [").append(messageId).append("] "); + if (from != null) + buf.append("from [").append(getName(from)).append("] "); + buf.append("expiring on [").append(getTime(expiration)).append("] valid? ").append(isValid); + addEntry(buf.toString()); + if (messageType.equals("net.i2p.data.i2np.TunnelMessage")) { + //_log.warn("ReceiveMessage tunnel message ["+messageId+"]", new Exception("Receive tunnel")); } } public void receiveMessage(String messageType, long messageId, Date expiration, boolean isValid) { - receiveMessage(messageType, messageId, expiration, null, isValid); + receiveMessage(messageType, messageId, expiration, null, isValid); } /** @@ -410,12 +387,12 @@ public class MessageHistory { * @param containerMessageId the unique message id of the message */ public void wrap(String bodyMessageType, long bodyMessageId, String containerMessageType, long containerMessageId) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("Wrap message [").append(bodyMessageType).append("] id [").append(bodyMessageId).append("] "); - buf.append("in [").append(containerMessageType).append("] id [").append(containerMessageId).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("Wrap message [").append(bodyMessageType).append("] id [").append(bodyMessageId).append("] "); + buf.append("in [").append(containerMessageType).append("] id [").append(containerMessageId).append("]"); + addEntry(buf.toString()); } /** @@ -423,11 +400,11 @@ public class MessageHistory { * */ public void receivePayloadMessage(long messageId) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(64); - buf.append(getPrefix()); - buf.append("Receive payload message [").append(messageId).append("]"); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(64); + buf.append(getPrefix()); + buf.append("Receive payload message [").append(messageId).append("]"); + addEntry(buf.toString()); } /** @@ -438,11 +415,11 @@ public class MessageHistory { * @param timeToSend how long it took to send the message */ public void sendPayloadMessage(long messageId, boolean successfullySent, long timeToSend) { - if (!_doLog) return; - StringBuffer buf = new StringBuffer(128); - buf.append(getPrefix()); - buf.append("Send payload message in [").append(messageId).append("] in [").append(timeToSend).append("] successfully? ").append(successfullySent); - addEntry(buf.toString()); + if (!_doLog) return; + StringBuffer buf = new StringBuffer(128); + buf.append(getPrefix()); + buf.append("Send payload message in [").append(messageId).append("] in [").append(timeToSend).append("] successfully? ").append(successfullySent); + addEntry(buf.toString()); } /** @@ -450,27 +427,27 @@ public class MessageHistory { * */ private final static String getName(Hash router) { - if (router == null) return "unknown"; - String str = router.toBase64(); - if ( (str == null) || (str.length() < 6) ) return "invalid"; - return str.substring(0, 6); + if (router == null) return "unknown"; + String str = router.toBase64(); + if ( (str == null) || (str.length() < 6) ) return "invalid"; + return str.substring(0, 6); } private final String getPrefix() { - StringBuffer buf = new StringBuffer(48); - buf.append(getTime(new Date(Clock.getInstance().now()))); - buf.append(' ').append(_localIdent).append(": "); - return buf.toString(); + StringBuffer buf = new StringBuffer(48); + buf.append(getTime(new Date(_context.clock().now()))); + buf.append(' ').append(_localIdent).append(": "); + return buf.toString(); } private final static SimpleDateFormat _fmt = new SimpleDateFormat("yy/MM/dd.HH:mm:ss.SSS"); static { - _fmt.setTimeZone(TimeZone.getTimeZone("GMT")); + _fmt.setTimeZone(TimeZone.getTimeZone("GMT")); } private final static String getTime(Date when) { - synchronized (_fmt) { - return _fmt.format(when); - } + synchronized (_fmt) { + return _fmt.format(when); + } } /** @@ -479,27 +456,27 @@ public class MessageHistory { * */ private void addEntry(String entry) { - if (entry == null) return; - int sz = 0; - synchronized (_unwrittenEntries) { - _unwrittenEntries.add(entry); - sz = _unwrittenEntries.size(); - } - if (sz > FLUSH_SIZE) - flushEntries(); + if (entry == null) return; + int sz = 0; + synchronized (_unwrittenEntries) { + _unwrittenEntries.add(entry); + sz = _unwrittenEntries.size(); + } + if (sz > FLUSH_SIZE) + flushEntries(); } /** * Write out any unwritten entries, and clear the pending list */ private void flushEntries() { - if (_doPause) return; - List entries = null; - synchronized (_unwrittenEntries) { - entries = new LinkedList(_unwrittenEntries); - _unwrittenEntries.clear(); - } - writeEntries(entries); + if (_doPause) return; + List entries = null; + synchronized (_unwrittenEntries) { + entries = new LinkedList(_unwrittenEntries); + _unwrittenEntries.clear(); + } + writeEntries(entries); } /** @@ -507,41 +484,46 @@ public class MessageHistory { * */ private void writeEntries(List entries) { - if (!_doLog) return; - FileOutputStream fos = null; - try { - fos = new FileOutputStream(_historyFile, true); - for (Iterator iter = entries.iterator(); iter.hasNext(); ) { - String entry = (String)iter.next(); - fos.write(entry.getBytes()); - fos.write(NL); - } - } catch (IOException ioe) { - _log.error("Error writing trace entries", ioe); - } finally { - if (fos != null) try { fos.close(); } catch (IOException ioe) {} - } + if (!_doLog) return; + FileOutputStream fos = null; + try { + fos = new FileOutputStream(_historyFile, true); + for (Iterator iter = entries.iterator(); iter.hasNext(); ) { + String entry = (String)iter.next(); + fos.write(entry.getBytes()); + fos.write(NL); + } + } catch (IOException ioe) { + _log.error("Error writing trace entries", ioe); + } finally { + if (fos != null) try { fos.close(); } catch (IOException ioe) {} + } } /** write out the message history once per minute, if not sooner */ private final static long WRITE_DELAY = 60*1000; - private static class WriteJob extends JobImpl { - public String getName() { return "Write History Entries"; } - public void runJob() { - MessageHistory.getInstance().flushEntries(); - MessageHistory.getInstance().updateSettings(); - requeue(WRITE_DELAY); - } + private class WriteJob extends JobImpl { + public WriteJob() { + super(MessageHistory.this._context); + } + public String getName() { return "Write History Entries"; } + public void runJob() { + flushEntries(); + updateSettings(); + requeue(WRITE_DELAY); + } } public static void main(String args[]) { - MessageHistory hist = new MessageHistory(new Hash(new byte[32]), "messageHistory.txt"); - MessageHistory.getInstance().setDoLog(false); - hist.addEntry("you smell before"); - hist.getInstance().setDoLog(true); - hist.addEntry("you smell after"); - hist.getInstance().setDoLog(false); - hist.addEntry("you smell finished"); - hist.flushEntries(); + RouterContext ctx = new RouterContext(null); + MessageHistory hist = new MessageHistory(ctx); + //, new Hash(new byte[32]), "messageHistory.txt"); + hist.setDoLog(false); + hist.addEntry("you smell before"); + hist.setDoLog(true); + hist.addEntry("you smell after"); + hist.setDoLog(false); + hist.addEntry("you smell finished"); + hist.flushEntries(); } } diff --git a/router/java/src/net/i2p/router/MessageValidator.java b/router/java/src/net/i2p/router/MessageValidator.java index 01191ef12..8dd8bc050 100644 --- a/router/java/src/net/i2p/router/MessageValidator.java +++ b/router/java/src/net/i2p/router/MessageValidator.java @@ -17,21 +17,29 @@ import net.i2p.util.Log; * */ public class MessageValidator { - private final static Log _log = new Log(MessageValidator.class); - private final static MessageValidator _instance = new MessageValidator(); - public final static MessageValidator getInstance() { return _instance; } - - /** + private Log _log; + private RouterContext _context; + /** * Expiration date (as a Long) to message id (as a Long). * The expiration date (key) must be unique, so on collision, increment the value. * This keeps messageIds around longer than they need to be, but hopefully not by much ;) * */ - private TreeMap _receivedIdExpirations = new TreeMap(); + private TreeMap _receivedIdExpirations; /** Message id (as a Long) */ - private Set _receivedIds = new HashSet(1024); + private Set _receivedIds; /** synchronize on this before adjusting the received id data */ - private Object _receivedIdLock = new Object(); + private Object _receivedIdLock; + + + public MessageValidator(RouterContext context) { + _log = context.logManager().getLog(MessageValidator.class); + _receivedIdExpirations = new TreeMap(); + _receivedIds = new HashSet(1024); + _receivedIdLock = new Object(); + _context = context; + } + /** * Determine if this message should be accepted as valid (not expired, not a duplicate) @@ -39,88 +47,87 @@ public class MessageValidator { * @return true if the message should be accepted as valid, false otherwise */ public boolean validateMessage(long messageId, long expiration) { - long now = Clock.getInstance().now(); - if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Rejecting message " + messageId + " because it expired " + (now-expiration) + "ms ago"); - return false; - } - - boolean isDuplicate = noteReception(messageId, expiration); - if (isDuplicate) { - if (_log.shouldLog(Log.WARN)) - _log.warn("Rejecting message " + messageId + " because it is a duplicate", new Exception("Duplicate origin")); - return false; - } else { - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Accepting message " + messageId + " because it is NOT a duplicate", new Exception("Original origin")); - return true; - } + long now = _context.clock().now(); + if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Rejecting message " + messageId + " because it expired " + (now-expiration) + "ms ago"); + return false; + } + + boolean isDuplicate = noteReception(messageId, expiration); + if (isDuplicate) { + if (_log.shouldLog(Log.WARN)) + _log.warn("Rejecting message " + messageId + " because it is a duplicate", new Exception("Duplicate origin")); + return false; + } else { + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Accepting message " + messageId + " because it is NOT a duplicate", new Exception("Original origin")); + return true; + } } /** * Note that we've received the message (which has the expiration given). - * This functionality will need to be reworked for I2P 3.0 when we take into + * This functionality will need to be reworked for I2P 3.0 when we take into * consideration messages with significant user specified delays (since we dont * want to keep an infinite number of messages in RAM, etc) * * @return true if we HAVE already seen this message, false if not */ private boolean noteReception(long messageId, long messageExpiration) { - Long id = new Long(messageId); - synchronized (_receivedIdLock) { - locked_cleanReceivedIds(Clock.getInstance().now() - Router.CLOCK_FUDGE_FACTOR); - if (_receivedIds.contains(id)) { - return true; - } else { - long date = messageExpiration; - while (_receivedIdExpirations.containsKey(new Long(date))) - date++; - _receivedIdExpirations.put(new Long(date), id); - _receivedIds.add(id); - return false; - } - } + Long id = new Long(messageId); + synchronized (_receivedIdLock) { + locked_cleanReceivedIds(_context.clock().now() - Router.CLOCK_FUDGE_FACTOR); + if (_receivedIds.contains(id)) { + return true; + } else { + long date = messageExpiration; + while (_receivedIdExpirations.containsKey(new Long(date))) + date++; + _receivedIdExpirations.put(new Long(date), id); + _receivedIds.add(id); + return false; + } + } } - + /** - * Clean the ids that we no longer need to keep track of to prevent replay + * Clean the ids that we no longer need to keep track of to prevent replay * attacks. * - */ + */ private void cleanReceivedIds() { - long now = Clock.getInstance().now() - Router.CLOCK_FUDGE_FACTOR ; - synchronized (_receivedIdLock) { - locked_cleanReceivedIds(now); - } + long now = _context.clock().now() - Router.CLOCK_FUDGE_FACTOR ; + synchronized (_receivedIdLock) { + locked_cleanReceivedIds(now); + } } - + /** - * Clean the ids that we no longer need to keep track of to prevent replay + * Clean the ids that we no longer need to keep track of to prevent replay * attacks - only call this from within a block synchronized on the received ID lock. * */ private void locked_cleanReceivedIds(long now) { - Set toRemoveIds = new HashSet(4); - Set toRemoveDates = new HashSet(4); - for (Iterator iter = _receivedIdExpirations.keySet().iterator(); iter.hasNext(); ) { - Long date = (Long)iter.next(); - if (date.longValue() <= now) { - // no need to keep track of things in the past - toRemoveDates.add(date); - toRemoveIds.add(_receivedIdExpirations.get(date)); - } else { - // the expiration is in the future, we still need to keep track of - // it to prevent replays - break; - } - } - for (Iterator iter = toRemoveDates.iterator(); iter.hasNext(); ) - _receivedIdExpirations.remove(iter.next()); - for (Iterator iter = toRemoveIds.iterator(); iter.hasNext(); ) - _receivedIds.remove(iter.next()); - if (_log.shouldLog(Log.INFO)) - _log.info("Cleaned out " + toRemoveDates.size() + " expired messageIds, leaving " + _receivedIds.size() + " remaining"); + Set toRemoveIds = new HashSet(4); + Set toRemoveDates = new HashSet(4); + for (Iterator iter = _receivedIdExpirations.keySet().iterator(); iter.hasNext(); ) { + Long date = (Long)iter.next(); + if (date.longValue() <= now) { + // no need to keep track of things in the past + toRemoveDates.add(date); + toRemoveIds.add(_receivedIdExpirations.get(date)); + } else { + // the expiration is in the future, we still need to keep track of + // it to prevent replays + break; + } + } + for (Iterator iter = toRemoveDates.iterator(); iter.hasNext(); ) + _receivedIdExpirations.remove(iter.next()); + for (Iterator iter = toRemoveIds.iterator(); iter.hasNext(); ) + _receivedIds.remove(iter.next()); + if (_log.shouldLog(Log.INFO)) + _log.info("Cleaned out " + toRemoveDates.size() + " expired messageIds, leaving " + _receivedIds.size() + " remaining"); } - } diff --git a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java index 7e78f2ae2..c00208dd6 100644 --- a/router/java/src/net/i2p/router/NetworkDatabaseFacade.java +++ b/router/java/src/net/i2p/router/NetworkDatabaseFacade.java @@ -23,9 +23,6 @@ import net.i2p.router.networkdb.kademlia.KademliaNetworkDatabaseFacade; * */ public abstract class NetworkDatabaseFacade implements Service { - private static NetworkDatabaseFacade _instance = new KademliaNetworkDatabaseFacade(); // NetworkDatabaseFacadeImpl(); - public static NetworkDatabaseFacade getInstance() { return _instance; } - /** * Return the RouterInfo structures for the routers closest to the given key. * At most maxNumRouters will be returned @@ -54,33 +51,35 @@ public abstract class NetworkDatabaseFacade implements Service { class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade { private Map _routers; + private RouterContext _context; - public DummyNetworkDatabaseFacade() { - _routers = new HashMap(); + public DummyNetworkDatabaseFacade(RouterContext ctx) { + _routers = new HashMap(); + _context = ctx; } public void shutdown() {} public void startup() { - RouterInfo info = Router.getInstance().getRouterInfo(); - _routers.put(info.getIdentity().getHash(), info); + RouterInfo info = _context.router().getRouterInfo(); + _routers.put(info.getIdentity().getHash(), info); } public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {} public LeaseSet lookupLeaseSetLocally(Hash key) { return null; } public void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) { - RouterInfo info = lookupRouterInfoLocally(key); - if (info == null) - JobQueue.getInstance().addJob(onFailedLookupJob); - else - JobQueue.getInstance().addJob(onFindJob); + RouterInfo info = lookupRouterInfoLocally(key); + if (info == null) + _context.jobQueue().addJob(onFailedLookupJob); + else + _context.jobQueue().addJob(onFindJob); } public RouterInfo lookupRouterInfoLocally(Hash key) { return (RouterInfo)_routers.get(key); } public void publish(LeaseSet localLeaseSet) {} public void publish(RouterInfo localRouterInfo) {} public LeaseSet store(Hash key, LeaseSet leaseSet) { return leaseSet; } public RouterInfo store(Hash key, RouterInfo routerInfo) { - _routers.put(key, routerInfo); - return routerInfo; + _routers.put(key, routerInfo); + return routerInfo; } public void unpublish(LeaseSet localLeaseSet) {} public void fail(Hash dbEntry) {} diff --git a/router/java/src/net/i2p/router/OutNetMessage.java b/router/java/src/net/i2p/router/OutNetMessage.java index 4e982f6f7..2639283c2 100644 --- a/router/java/src/net/i2p/router/OutNetMessage.java +++ b/router/java/src/net/i2p/router/OutNetMessage.java @@ -1,9 +1,9 @@ package net.i2p.router; /* * 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 + * 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. * */ @@ -32,7 +32,8 @@ import net.i2p.util.Log; * */ public class OutNetMessage { - private final static Log _log = new Log(OutNetMessage.class); + private Log _log; + private RouterContext _context; private RouterInfo _target; private I2NPMessage _message; private long _messageSize; @@ -49,53 +50,55 @@ public class OutNetMessage { private long _created; /** for debugging, contains a mapping of even name to Long (e.g. "begin sending", "handleOutbound", etc) */ private HashMap _timestamps; - /** - * contains a list of timestamp event names in the order they were fired - * (some JVMs have less than 10ms resolution, so the Long above doesn't guarantee order) + /** + * contains a list of timestamp event names in the order they were fired + * (some JVMs have less than 10ms resolution, so the Long above doesn't guarantee order) */ private List _timestampOrder; - public OutNetMessage() { - setTarget(null); - _message = null; - _messageSize = 0; - setPriority(-1); - setExpiration(-1); - setOnSendJob(null); - setOnFailedSendJob(null); - setOnReplyJob(null); - setOnFailedReplyJob(null); - setReplySelector(null); - _timestamps = new HashMap(8); - _timestampOrder = new LinkedList(); - _failedTransports = new HashSet(); - _sendBegin = 0; - _createdBy = new Exception("Created by"); - _created = Clock.getInstance().now(); - timestamp("Created"); + public OutNetMessage(RouterContext context) { + _context = context; + _log = context.logManager().getLog(OutNetMessage.class); + setTarget(null); + _message = null; + _messageSize = 0; + setPriority(-1); + setExpiration(-1); + setOnSendJob(null); + setOnFailedSendJob(null); + setOnReplyJob(null); + setOnFailedReplyJob(null); + setReplySelector(null); + _timestamps = new HashMap(8); + _timestampOrder = new LinkedList(); + _failedTransports = new HashSet(); + _sendBegin = 0; + _createdBy = new Exception("Created by"); + _created = context.clock().now(); + timestamp("Created"); } public void timestamp(String eventName) { - synchronized (_timestamps) { - _timestamps.put(eventName, new Long(Clock.getInstance().now())); - _timestampOrder.add(eventName); - } + synchronized (_timestamps) { + _timestamps.put(eventName, new Long(_context.clock().now())); + _timestampOrder.add(eventName); + } } public Map getTimestamps() { - synchronized (_timestamps) { - return (Map)_timestamps.clone(); - } + synchronized (_timestamps) { + return (Map)_timestamps.clone(); + } } public Long getTimestamp(String eventName) { - synchronized (_timestamps) { - return (Long)_timestamps.get(eventName); - } + synchronized (_timestamps) { + return (Long)_timestamps.get(eventName); + } } public Exception getCreatedBy() { return _createdBy; } /** - * Specifies the router to which the message should be delivered. + * Specifies the router to which the message should be delivered. * */ public RouterInfo getTarget() { return _target; } @@ -105,48 +108,48 @@ public class OutNetMessage { * */ public I2NPMessage getMessage() { return _message; } - public void setMessage(I2NPMessage msg) { - _message = msg; + public void setMessage(I2NPMessage msg) { + _message = msg; } - public long getMessageSize() { - if (_messageSize <= 0) { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages - _message.writeBytes(baos); - long sz = baos.size(); - baos.reset(); - _messageSize = sz; - } catch (DataFormatException dfe) { - _log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe); - } catch (IOException ioe) { - _log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe); - } - } - return _messageSize; + public long getMessageSize() { + if (_messageSize <= 0) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages + _message.writeBytes(baos); + long sz = baos.size(); + baos.reset(); + _messageSize = sz; + } catch (DataFormatException dfe) { + _log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe); + } catch (IOException ioe) { + _log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe); + } + } + return _messageSize; } - public byte[] getMessageData() { - if (_message == null) { - return null; - } else { - try { - ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages - _message.writeBytes(baos); - byte data[] = baos.toByteArray(); - baos.reset(); - return data; - } catch (DataFormatException dfe) { - _log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe); - } catch (IOException ioe) { - _log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe); - } - return null; - } + public byte[] getMessageData() { + if (_message == null) { + return null; + } else { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages + _message.writeBytes(baos); + byte data[] = baos.toByteArray(); + baos.reset(); + return data; + } catch (DataFormatException dfe) { + _log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe); + } catch (IOException ioe) { + _log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe); + } + return null; + } } /** * Specify the priority of the message, where higher numbers are higher - * priority. Higher priority messages should be delivered before lower + * priority. Higher priority messages should be delivered before lower * priority ones, though some algorithm may be used to avoid starvation. * */ @@ -154,15 +157,15 @@ public class OutNetMessage { public void setPriority(int priority) { _priority = priority; } /** * Specify the # ms since the epoch after which if the message has not been - * sent the OnFailedSend job should be fired and the message should be - * removed from the pool. If the message has already been sent, this + * sent the OnFailedSend job should be fired and the message should be + * removed from the pool. If the message has already been sent, this * expiration is ignored and the expiration from the ReplySelector is used. * */ public long getExpiration() { return _expiration; } public void setExpiration(long expiration) { _expiration = expiration; } /** - * After the message is successfully passed to the router specified, the + * After the message is successfully passed to the router specified, the * given job is enqueued. * */ @@ -199,74 +202,74 @@ public class OutNetMessage { /** when did the sending process begin */ public long getSendBegin() { return _sendBegin; } - public void beginSend() { _sendBegin = Clock.getInstance().now(); } + public void beginSend() { _sendBegin = _context.clock().now(); } public long getCreated() { return _created; } - public long getLifetime() { return Clock.getInstance().now() - _created; } + public long getLifetime() { return _context.clock().now() - _created; } public String toString() { - StringBuffer buf = new StringBuffer(128); - buf.append("[OutNetMessage contains "); - if (_message == null) { - buf.append("*no message*"); - } else { - buf.append("a ").append(_messageSize).append(" byte "); - buf.append(_message.getClass().getName()); - } - buf.append(" expiring on ").append(new Date(_expiration)); - buf.append(" failed delivery on transports ").append(_failedTransports); - if (_target == null) - buf.append(" targetting no one in particular..."); - else - buf.append(" targetting ").append(_target.getIdentity().getHash().toBase64()); - if (_onReply != null) - buf.append(" with onReply job: ").append(_onReply); - if (_onSend != null) - buf.append(" with onSend job: ").append(_onSend); - if (_onFailedReply != null) - buf.append(" with onFailedReply job: ").append(_onFailedReply); - if (_onFailedSend != null) - buf.append(" with onFailedSend job: ").append(_onFailedSend); - buf.append(" {timestamps: \n"); - synchronized (_timestamps) { - long lastWhen = -1; - for (int i = 0; i < _timestampOrder.size(); i++) { - String name = (String)_timestampOrder.get(i); - Long when = (Long)_timestamps.get(name); - buf.append("\t["); - long diff = when.longValue() - lastWhen; - if ( (lastWhen > 0) && (diff > 500) ) - buf.append("**"); - if (lastWhen > 0) - buf.append(diff); - else - buf.append(0); - buf.append("ms: \t").append(name).append('=').append(formatDate(when.longValue())).append("]\n"); - lastWhen = when.longValue(); - } - } - buf.append("}"); - buf.append("]"); - return buf.toString(); + StringBuffer buf = new StringBuffer(128); + buf.append("[OutNetMessage contains "); + if (_message == null) { + buf.append("*no message*"); + } else { + buf.append("a ").append(_messageSize).append(" byte "); + buf.append(_message.getClass().getName()); + } + buf.append(" expiring on ").append(new Date(_expiration)); + buf.append(" failed delivery on transports ").append(_failedTransports); + if (_target == null) + buf.append(" targetting no one in particular..."); + else + buf.append(" targetting ").append(_target.getIdentity().getHash().toBase64()); + if (_onReply != null) + buf.append(" with onReply job: ").append(_onReply); + if (_onSend != null) + buf.append(" with onSend job: ").append(_onSend); + if (_onFailedReply != null) + buf.append(" with onFailedReply job: ").append(_onFailedReply); + if (_onFailedSend != null) + buf.append(" with onFailedSend job: ").append(_onFailedSend); + buf.append(" {timestamps: \n"); + synchronized (_timestamps) { + long lastWhen = -1; + for (int i = 0; i < _timestampOrder.size(); i++) { + String name = (String)_timestampOrder.get(i); + Long when = (Long)_timestamps.get(name); + buf.append("\t["); + long diff = when.longValue() - lastWhen; + if ( (lastWhen > 0) && (diff > 500) ) + buf.append("**"); + if (lastWhen > 0) + buf.append(diff); + else + buf.append(0); + buf.append("ms: \t").append(name).append('=').append(formatDate(when.longValue())).append("]\n"); + lastWhen = when.longValue(); + } + } + buf.append("}"); + buf.append("]"); + return buf.toString(); } private final static SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss.SSS"); private final static String formatDate(long when) { - Date d = new Date(when); - synchronized (_fmt) { - return _fmt.format(d); - } + Date d = new Date(when); + synchronized (_fmt) { + return _fmt.format(d); + } } public int hashCode() { - int rv = 0; - rv += DataHelper.hashCode(_message); - rv += DataHelper.hashCode(_target); - // the others are pretty much inconsequential - return rv; + int rv = 0; + rv += DataHelper.hashCode(_message); + rv += DataHelper.hashCode(_target); + // the others are pretty much inconsequential + return rv; } public boolean equals(Object obj) { - return obj == this; // two OutNetMessages are different even if they contain the same message + return obj == this; // two OutNetMessages are different even if they contain the same message } } diff --git a/router/java/src/net/i2p/router/OutNetMessagePool.java b/router/java/src/net/i2p/router/OutNetMessagePool.java index 86897e2d2..1b76f90ad 100644 --- a/router/java/src/net/i2p/router/OutNetMessagePool.java +++ b/router/java/src/net/i2p/router/OutNetMessagePool.java @@ -26,13 +26,12 @@ import net.i2p.util.Log; * */ public class OutNetMessagePool { - private final static Log _log = new Log(OutNetMessagePool.class); - private static OutNetMessagePool _instance = new OutNetMessagePool(); - public static OutNetMessagePool getInstance() { return _instance; } - private TreeMap _messageLists; // priority --> List of OutNetMessage objects, where HIGHEST priority first + private Log _log; + private RouterContext _context; - private OutNetMessagePool() { - _messageLists = new TreeMap(new ReverseIntegerComparator()); + public OutNetMessagePool(RouterContext context) { + _context = context; + _log = _context.logManager().getLog(OutNetMessagePool.class); } /** @@ -40,19 +39,7 @@ public class OutNetMessagePool { * */ public OutNetMessage getNext() { - synchronized (_messageLists) { - if (_messageLists.size() <= 0) return null; - for (Iterator iter = _messageLists.keySet().iterator(); iter.hasNext(); ) { - Integer priority = (Integer)iter.next(); - List messages = (List)_messageLists.get(priority); - if (messages.size() > 0) { - _log.debug("Found a message of priority " + priority); - return (OutNetMessage)messages.remove(0); - } - } - // no messages of any priority - return null; - } + return null; } /** @@ -60,45 +47,35 @@ public class OutNetMessagePool { * */ public void add(OutNetMessage msg) { - boolean valid = validate(msg); - if (!valid) return; - if (true) { // skip the pool - MessageSelector selector = msg.getReplySelector(); - if (selector != null) { - OutboundMessageRegistry.getInstance().registerPending(msg); - } - CommSystemFacade.getInstance().processMessage(msg); - return; - } - - synchronized (_messageLists) { - Integer pri = new Integer(msg.getPriority()); - if ( (_messageLists.size() <= 0) || (!_messageLists.containsKey(pri)) ) - _messageLists.put(new Integer(msg.getPriority()), new ArrayList(32)); - List messages = (List)_messageLists.get(pri); - messages.add(msg); - } + boolean valid = validate(msg); + if (!valid) return; + MessageSelector selector = msg.getReplySelector(); + if (selector != null) { + _context.messageRegistry().registerPending(msg); + } + _context.commSystem().processMessage(msg); + return; } private boolean validate(OutNetMessage msg) { - if (msg == null) return false; - if (msg.getMessage() == null) { - _log.error("Null message in the OutNetMessage: " + msg, new Exception("Someone fucked up")); - return false; - } - if (msg.getTarget() == null) { - _log.error("No target in the OutNetMessage: " + msg, new Exception("Definitely a fuckup")); - return false; - } - if (msg.getPriority() < 0) { - _log.warn("Priority less than 0? sounds like nonsense to me... " + msg, new Exception("Negative priority")); - return false; - } - if (msg.getExpiration() <= Clock.getInstance().now()) { - _log.error("Already expired! wtf: " + msg, new Exception("Expired message")); - return false; - } - return true; + if (msg == null) return false; + if (msg.getMessage() == null) { + _log.error("Null message in the OutNetMessage: " + msg, new Exception("Someone fucked up")); + return false; + } + if (msg.getTarget() == null) { + _log.error("No target in the OutNetMessage: " + msg, new Exception("Definitely a fuckup")); + return false; + } + if (msg.getPriority() < 0) { + _log.warn("Priority less than 0? sounds like nonsense to me... " + msg, new Exception("Negative priority")); + return false; + } + if (msg.getExpiration() <= _context.clock().now()) { + _log.error("Already expired! wtf: " + msg, new Exception("Expired message")); + return false; + } + return true; } /** @@ -106,43 +83,14 @@ public class OutNetMessagePool { * */ public void clearExpired() { - long now = Clock.getInstance().now(); - List jobsToEnqueue = new ArrayList(); - synchronized (_messageLists) { - for (Iterator iter = _messageLists.values().iterator(); iter.hasNext();) { - List toRemove = new ArrayList(); - List messages = (List)iter.next(); - for (Iterator msgIter = messages.iterator(); msgIter.hasNext(); ) { - OutNetMessage msg = (OutNetMessage)msgIter.next(); - if (msg.getExpiration() <= now) { - _log.warn("Outbound network message expired: " + msg); - toRemove.add(msg); - jobsToEnqueue.add(msg.getOnFailedSendJob()); - } - } - messages.removeAll(toRemove); - } - } - for (int i = 0; i < jobsToEnqueue.size(); i++) { - Job j = (Job)jobsToEnqueue.get(i); - JobQueue.getInstance().addJob(j); - } + // noop } /** * Retrieve the number of messages, regardless of priority. * */ - public int getCount() { - int size = 0; - synchronized (_messageLists) { - for (Iterator iter = _messageLists.values().iterator(); iter.hasNext(); ) { - List lst = (List)iter.next(); - size += lst.size(); - } - } - return size; - } + public int getCount() { return 0; } /** * Retrieve the number of messages at the given priority. This can be used for @@ -150,45 +98,17 @@ public class OutNetMessagePool { * where all of these 'spare' messages are of the same priority. * */ - public int getCount(int priority) { - synchronized (_messageLists) { - Integer pri = new Integer(priority); - List messages = (List)_messageLists.get(pri); - if (messages == null) - return 0; - else - return messages.size(); - } - } + public int getCount(int priority) { return 0; } - public void dumpPoolInfo() { - StringBuffer buf = new StringBuffer(); - buf.append("\nDumping Outbound Network Message Pool. Total # message: ").append(getCount()).append("\n"); - synchronized (_messageLists) { - for (Iterator iter = _messageLists.keySet().iterator(); iter.hasNext();) { - Integer pri = (Integer)iter.next(); - List messages = (List)_messageLists.get(pri); - if (messages.size() > 0) { - buf.append("Messages of priority ").append(pri).append(": ").append(messages.size()).append("\n"); - buf.append("---------------------------\n"); - for (Iterator msgIter = messages.iterator(); msgIter.hasNext(); ) { - OutNetMessage msg = (OutNetMessage)msgIter.next(); - buf.append("Message ").append(msg.getMessage()).append("\n\n"); - } - buf.append("---------------------------\n"); - } - } - } - _log.debug(buf.toString()); - } + public void dumpPoolInfo() { return; } private static class ReverseIntegerComparator implements Comparator { - public int compare(Object lhs, Object rhs) { - if ( (lhs == null) || (rhs == null) ) return 0; // invalid, but never used - if ( !(lhs instanceof Integer) || !(rhs instanceof Integer)) return 0; - Integer lv = (Integer)lhs; - Integer rv = (Integer)rhs; - return - (lv.compareTo(rv)); - } + public int compare(Object lhs, Object rhs) { + if ( (lhs == null) || (rhs == null) ) return 0; // invalid, but never used + if ( !(lhs instanceof Integer) || !(rhs instanceof Integer)) return 0; + Integer lv = (Integer)lhs; + Integer rv = (Integer)rhs; + return - (lv.compareTo(rv)); + } } } diff --git a/router/java/src/net/i2p/router/PeerManagerFacade.java b/router/java/src/net/i2p/router/PeerManagerFacade.java index 474babb15..d75a73258 100644 --- a/router/java/src/net/i2p/router/PeerManagerFacade.java +++ b/router/java/src/net/i2p/router/PeerManagerFacade.java @@ -18,23 +18,19 @@ import net.i2p.router.peermanager.PeerManagerFacadeImpl; * includes periodically queueing up outbound messages to the peers to test them. * */ -public abstract class PeerManagerFacade implements Service { - private static PeerManagerFacade _instance = new PeerManagerFacadeImpl(); - public static PeerManagerFacade getInstance() { return _instance; } - +public interface PeerManagerFacade extends Service { /** * Select peers from the manager's existing routing tables according to * the specified criteria. This call DOES block. * * @return List of Hash objects of the RouterIdentity for matching peers */ - public abstract List selectPeers(PeerSelectionCriteria criteria); - public String renderStatusHTML() { return ""; } + public List selectPeers(PeerSelectionCriteria criteria); } -class DummyPeerManagerFacade extends PeerManagerFacade { +class DummyPeerManagerFacade implements PeerManagerFacade { public void shutdown() {} public void startup() {} - + public String renderStatusHTML() { return ""; } public List selectPeers(PeerSelectionCriteria criteria) { return null; } } diff --git a/router/java/src/net/i2p/router/ProfileManager.java b/router/java/src/net/i2p/router/ProfileManager.java index 57251e667..c49c85bd7 100644 --- a/router/java/src/net/i2p/router/ProfileManager.java +++ b/router/java/src/net/i2p/router/ProfileManager.java @@ -11,71 +11,64 @@ package net.i2p.router; import java.util.Properties; import net.i2p.data.Hash; -import net.i2p.router.peermanager.ProfileManagerImpl; -public abstract class ProfileManager { - private final static ProfileManager _instance = new ProfileManagerImpl(); - public static ProfileManager getInstance() { return _instance; } - - /** is this peer failing or already dropped? */ - public abstract boolean isFailing(Hash peer); - +public interface ProfileManager { /** * Note that it took msToSend to send a message of size bytesSent to the peer over the transport. * This should only be called if the transport considered the send successful. * */ - public abstract void messageSent(Hash peer, String transport, long msToSend, long bytesSent); + void messageSent(Hash peer, String transport, long msToSend, long bytesSent); /** * Note that the router failed to send a message to the peer over the transport specified * */ - public abstract void messageFailed(Hash peer, String transport); + void messageFailed(Hash peer, String transport); /** * Note that the router failed to send a message to the peer over any transport * */ - public abstract void messageFailed(Hash peer); + void messageFailed(Hash peer); /** * Note that there was some sort of communication error talking with the peer * */ - public abstract void commErrorOccurred(Hash peer); + void commErrorOccurred(Hash peer); /** * Note that the router agreed to participate in a tunnel * */ - public abstract void tunnelJoined(Hash peer, long responseTimeMs); + void tunnelJoined(Hash peer, long responseTimeMs); /** * Note that a router explicitly rejected joining a tunnel * */ - public abstract void tunnelRejected(Hash peer, long responseTimeMs); + void tunnelRejected(Hash peer, long responseTimeMs); /** * Note that the peer participated in a tunnel that failed. Its failure may not have * been the peer's fault however. * */ - public abstract void tunnelFailed(Hash peer); + void tunnelFailed(Hash peer); /** * Note that the peer was able to return the valid data for a db lookup * */ - public abstract void dbLookupSuccessful(Hash peer, long responseTimeMs); + void dbLookupSuccessful(Hash peer, long responseTimeMs); /** * Note that the peer was unable to reply to a db lookup - either with data or with * a lookupReply redirecting the user elsewhere * */ - public abstract void dbLookupFailed(Hash peer); + void dbLookupFailed(Hash peer); /** * Note that the peer replied to a db lookup with a redirect to other routers, where @@ -85,39 +78,39 @@ public abstract class ProfileManager { * asked them not to send us, but they did anyway * */ - public abstract void dbLookupReply(Hash peer, int newPeers, int oldPeers, int invalid, int duplicate, long responseTimeMs); + void dbLookupReply(Hash peer, int newPeers, int oldPeers, int invalid, int duplicate, long responseTimeMs); /** * Note that the local router received a db lookup from the given peer * */ - public abstract void dbLookupReceived(Hash peer); + void dbLookupReceived(Hash peer); /** * Note that the local router received an unprompted db store from the given peer * */ - public abstract void dbStoreReceived(Hash peer, boolean wasNewKey); + void dbStoreReceived(Hash peer, boolean wasNewKey); /** * Note that we've confirmed a successful send of db data to the peer (though we haven't * necessarily requested it again from them, so they /might/ be lying) * */ - public abstract void dbStoreSent(Hash peer, long responseTimeMs); + void dbStoreSent(Hash peer, long responseTimeMs); /** * Note that we were unable to confirm a successful send of db data to * the peer, at least not within our timeout period * */ - public abstract void dbStoreFailed(Hash peer); + void dbStoreFailed(Hash peer); /** * Note that the local router received a reference to the given peer, either * through an explicit dbStore or in a dbLookupReply */ - public abstract void heardAbout(Hash peer); + void heardAbout(Hash peer); /** * Note that the router received a message from the given peer on the specified @@ -126,8 +119,8 @@ public abstract class ProfileManager { * available * */ - public abstract void messageReceived(Hash peer, String style, long msToReceive, int bytesRead); + void messageReceived(Hash peer, String style, long msToReceive, int bytesRead); /** provide a simple summary of a number of peers, suitable for publication in the netDb */ - public abstract Properties summarizePeers(int numPeers); + Properties summarizePeers(int numPeers); } diff --git a/router/java/src/net/i2p/router/Router.java b/router/java/src/net/i2p/router/Router.java index 4d69ecfed..8161a5d85 100644 --- a/router/java/src/net/i2p/router/Router.java +++ b/router/java/src/net/i2p/router/Router.java @@ -54,14 +54,14 @@ import net.i2p.util.RandomSource; * */ public class Router { - private final static Log _log = new Log(Router.class); - private final static Router _instance = new Router(); - public static Router getInstance() { return _instance; } + private Log _log; + private RouterContext _context; private Properties _config; private String _configFilename; private RouterInfo _routerInfo; private long _started; private boolean _higherVersionSeen; + private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper; public final static String PROP_CONFIG_FILE = "router.configLocation"; @@ -73,16 +73,19 @@ public class Router { public final static String PROP_KEYS_FILENAME = "router.keys.location"; public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys"; - private Router() { - _config = new Properties(); - _configFilename = System.getProperty(PROP_CONFIG_FILE, "router.config"); - _routerInfo = null; - _higherVersionSeen = false; + public Router() { // grumble about sun's java caching DNS entries *forever* System.setProperty("sun.net.inetaddr.ttl", "0"); System.setProperty("networkaddress.cache.ttl", "0"); // (no need for keepalive) System.setProperty("http.keepAlive", "false"); + _config = new Properties(); + _context = new RouterContext(this); + _configFilename = _context.getProperty(PROP_CONFIG_FILE, "router.config"); + _routerInfo = null; + _higherVersionSeen = false; + _log = _context.logManager().getLog(Router.class); + _sessionKeyPersistenceHelper = new SessionKeyPersistenceHelper(_context); } public String getConfigFilename() { return _configFilename; } @@ -97,7 +100,7 @@ public class Router { public void setRouterInfo(RouterInfo info) { _routerInfo = info; if (info != null) - JobQueue.getInstance().addJob(new PersistRouterInfoJob()); + _context.jobQueue().addJob(new PersistRouterInfoJob()); } /** @@ -110,10 +113,10 @@ public class Router { public long getWhenStarted() { return _started; } /** wall clock uptime */ - public long getUptime() { return Clock.getInstance().now() - Clock.getInstance().getOffset() - _started; } + public long getUptime() { return _context.clock().now() - _context.clock().getOffset() - _started; } private void runRouter() { - _started = Clock.getInstance().now(); + _started = _context.clock().now(); Runtime.getRuntime().addShutdownHook(new ShutdownHook()); I2PThread.setOOMEventListener(new I2PThread.OOMEventListener() { public void outOfMemory(OutOfMemoryError oom) { @@ -123,21 +126,22 @@ public class Router { }); setupHandlers(); startupQueue(); - JobQueue.getInstance().addJob(new CoallesceStatsJob()); - JobQueue.getInstance().addJob(new UpdateRoutingKeyModifierJob()); + _context.jobQueue().addJob(new CoallesceStatsJob()); + _context.jobQueue().addJob(new UpdateRoutingKeyModifierJob()); warmupCrypto(); - SessionKeyPersistenceHelper.getInstance().startup(); - JobQueue.getInstance().addJob(new StartupJob()); + _sessionKeyPersistenceHelper.startup(); + _context.jobQueue().addJob(new StartupJob(_context)); } /** * coallesce the stats framework every minute * */ - private final static class CoallesceStatsJob extends JobImpl { + private final class CoallesceStatsJob extends JobImpl { + public CoallesceStatsJob() { super(Router.this._context); } public String getName() { return "Coallesce stats"; } public void runJob() { - StatManager.getInstance().coallesceStats(); + Router.this._context.statManager().coallesceStats(); requeue(60*1000); } } @@ -147,15 +151,16 @@ public class Router { * This is done here because we want to make sure the key is updated before anyone * uses it. */ - private final static class UpdateRoutingKeyModifierJob extends JobImpl { + private final class UpdateRoutingKeyModifierJob extends JobImpl { private Calendar _cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); + public UpdateRoutingKeyModifierJob() { super(Router.this._context); } public String getName() { return "Update Routing Key Modifier"; } public void runJob() { - RoutingKeyGenerator.getInstance().generateDateBasedModData(); + Router.this._context.routingKeyGenerator().generateDateBasedModData(); requeue(getTimeTillMidnight()); } private long getTimeTillMidnight() { - long now = Clock.getInstance().now(); + long now = Router.this._context.clock().now(); _cal.setTime(new Date(now)); _cal.add(Calendar.DATE, 1); _cal.set(Calendar.HOUR_OF_DAY, 0); @@ -175,18 +180,18 @@ public class Router { } private void warmupCrypto() { - RandomSource.getInstance().nextBoolean(); + _context.random().nextBoolean(); new DHSessionKeyBuilder(); // load the class so it starts the precalc process } private void startupQueue() { - JobQueue.getInstance().runQueue(1); + _context.jobQueue().runQueue(1); } private void setupHandlers() { - InNetMessagePool.getInstance().registerHandlerJobBuilder(GarlicMessage.MESSAGE_TYPE, new GarlicMessageHandler()); - InNetMessagePool.getInstance().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler()); - InNetMessagePool.getInstance().registerHandlerJobBuilder(SourceRouteReplyMessage.MESSAGE_TYPE, new SourceRouteReplyMessageHandler()); + _context.inNetMessagePool().registerHandlerJobBuilder(GarlicMessage.MESSAGE_TYPE, new GarlicMessageHandler(_context)); + _context.inNetMessagePool().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler(_context)); + _context.inNetMessagePool().registerHandlerJobBuilder(SourceRouteReplyMessage.MESSAGE_TYPE, new SourceRouteReplyMessageHandler(_context)); } public String renderStatusHTML() { @@ -214,9 +219,9 @@ public class Router { if ( (_routerInfo != null) && (_routerInfo.getIdentity() != null) ) buf.append("Router: ").append(_routerInfo.getIdentity().getHash().toBase64()).append("
\n"); - buf.append("As of: ").append(new Date(Clock.getInstance().now())).append(" (uptime: ").append(DataHelper.formatDuration(getUptime())).append(")
\n"); + buf.append("As of: ").append(new Date(_context.clock().now())).append(" (uptime: ").append(DataHelper.formatDuration(getUptime())).append(")
\n"); buf.append("Started on: ").append(new Date(getWhenStarted())).append("
\n"); - buf.append("Clock offset: ").append(Clock.getInstance().getOffset()).append("ms (OS time: ").append(new Date(Clock.getInstance().now() - Clock.getInstance().getOffset())).append(")
\n"); + buf.append("Clock offset: ").append(_context.clock().getOffset()).append("ms (OS time: ").append(new Date(_context.clock().now() - _context.clock().getOffset())).append(")
\n"); long tot = Runtime.getRuntime().totalMemory()/1024; long free = Runtime.getRuntime().freeMemory()/1024; buf.append("Memory: In use: ").append((tot-free)).append("KB Free: ").append(free).append("KB
\n"); @@ -225,8 +230,8 @@ public class Router { buf.append("HIGHER VERSION SEEN - please check to see if there is a new release out
\n"); buf.append("

Bandwidth

\n"); - long sent = BandwidthLimiter.getInstance().getTotalSendBytes(); - long received = BandwidthLimiter.getInstance().getTotalReceiveBytes(); + long sent = _context.bandwidthLimiter().getTotalSendBytes(); + long received = _context.bandwidthLimiter().getTotalReceiveBytes(); buf.append("