big ol' update to strip out the singletons, replacing them with

a rooted app context.  The core itself has its own I2PAppContext
(see its javadoc for, uh, docs), and the router extends that to
expose the router's singletons.  The main point of this is to
make it so that we can run multiple routers in the same JVM, even
to allow different apps in the same JVM to switch singleton
implementations (e.g. run some routers with one set of profile
calculators, and other routers with a different one).
There is still some work to be done regarding the actual boot up
of multiple routers in a JVM, as well as their configuration,
though the plan is to have the RouterContext override the
I2PAppContext's getProperty/getPropertyNames methods to read from
a config file (seperate ones per context) instead of using the
System.getProperty that the base I2PAppContext uses.
Once the multi-router is working, i'll shim in a VMCommSystem
that doesn't depend upon sockets or threads to read/write (and
that uses configurable message send delays / disconnects / etc,
perhaps using data from the routerContext.getProperty to drive it).
I could hold off until the sim is all working, but there's a
truckload of changes in here and I hate dealing with conflicts ;)
Everything works - I've been running 'er for a while and kicked
the tires a bit, but if you see something amiss, please let me
know.
This commit is contained in:
jrandom
2004-04-24 11:54:35 +00:00
committed by zzz
parent c29a6b95ae
commit 393b1d7674
217 changed files with 16662 additions and 15452 deletions

View File

@ -53,7 +53,7 @@ public class HTTPListener extends Thread {
private boolean proxyUsed = false; 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. * @return Whether this is the first proxy use, no doubt.
*/ */
public boolean firstProxyUse() { public boolean firstProxyUse() {

View File

@ -19,6 +19,7 @@ import net.i2p.httptunnel.SocketManagerProducer;
import net.i2p.httptunnel.filter.Filter; import net.i2p.httptunnel.filter.Filter;
import net.i2p.httptunnel.filter.NullFilter; import net.i2p.httptunnel.filter.NullFilter;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Handler for browsing Eepsites. * Handler for browsing Eepsites.
@ -26,6 +27,7 @@ import net.i2p.util.Log;
public class EepHandler { public class EepHandler {
private static final Log _log = new Log(EepHandler.class); private static final Log _log = new Log(EepHandler.class);
private static I2PAppContext _context = new I2PAppContext();
protected ErrorHandler errorHandler; protected ErrorHandler errorHandler;
@ -44,7 +46,7 @@ public class EepHandler {
public void handle(Request req, HTTPListener httpl, OutputStream out, public void handle(Request req, HTTPListener httpl, OutputStream out,
/* boolean fromProxy, */String destination) throws IOException { /* boolean fromProxy, */String destination) throws IOException {
SocketManagerProducer smp = httpl.getSMP(); SocketManagerProducer smp = httpl.getSMP();
Destination dest = NamingService.getInstance().lookup(destination); Destination dest = _context.namingService().lookup(destination);
if (dest == null) { if (dest == null) {
errorHandler.handle(req, httpl, out, "Could not lookup host: " + destination); errorHandler.handle(req, httpl, out, "Could not lookup host: " + destination);
return; return;
@ -66,8 +68,8 @@ public class EepHandler {
* @return boolean, true if something was written, false otherwise. * @return boolean, true if something was written, false otherwise.
* @throws IOException * @throws IOException
*/ */
public boolean handle(Request req, Filter f, OutputStream out, Destination dest, I2PSocketManager sm) public boolean handle(Request req, Filter f, OutputStream out, Destination dest,
throws IOException { I2PSocketManager sm) throws IOException {
I2PSocket s = null; I2PSocket s = null;
boolean written = false; boolean written = false;
try { try {

View File

@ -12,6 +12,7 @@ import net.i2p.httptunnel.SocketManagerProducer;
import net.i2p.httptunnel.filter.Filter; import net.i2p.httptunnel.filter.Filter;
import net.i2p.httptunnel.filter.NullFilter; import net.i2p.httptunnel.filter.NullFilter;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Handler for proxying "normal" HTTP requests. * Handler for proxying "normal" HTTP requests.
@ -19,6 +20,7 @@ import net.i2p.util.Log;
public class ProxyHandler extends EepHandler { public class ProxyHandler extends EepHandler {
private static final Log _log = new Log(ErrorHandler.class); private static final Log _log = new Log(ErrorHandler.class);
private static I2PAppContext _context = new I2PAppContext();
/* package private */ProxyHandler(ErrorHandler eh) { /* package private */ProxyHandler(ErrorHandler eh) {
super(eh); super(eh);
@ -48,6 +50,6 @@ public class ProxyHandler extends EepHandler {
private Destination findProxy() { private Destination findProxy() {
//FIXME! //FIXME!
return NamingService.getInstance().lookup("squid.i2p"); return _context.namingService().lookup("squid.i2p");
} }
} }

View File

@ -29,7 +29,7 @@ public class RootHandler {
private static RootHandler instance; private static RootHandler instance;
/** /**
* Singleton stuff . . . * Singleton stuff
* @return the one and only instance, yay! * @return the one and only instance, yay!
*/ */
public static synchronized RootHandler getInstance() { public static synchronized RootHandler getInstance() {

View File

@ -49,6 +49,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.I2PException; import net.i2p.I2PException;
import net.i2p.client.I2PClient; import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory; import net.i2p.client.I2PClientFactory;
@ -65,6 +66,7 @@ import net.i2p.util.Log;
public class I2PTunnel implements Logging, EventDispatcher { public class I2PTunnel implements Logging, EventDispatcher {
private final static Log _log = new Log(I2PTunnel.class); private final static Log _log = new Log(I2PTunnel.class);
private final EventDispatcherImpl _event = new EventDispatcherImpl(); private final EventDispatcherImpl _event = new EventDispatcherImpl();
private static I2PAppContext _context = new I2PAppContext();
public static final int PACKET_DELAY = 100; public static final int PACKET_DELAY = 100;
@ -954,7 +956,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
} }
} else { } else {
// ask naming service // ask naming service
NamingService inst = NamingService.getInstance(); NamingService inst = _context.namingService();
return inst.lookup(name); return inst.lookup(name);
} }
} }

View File

@ -23,6 +23,7 @@ import net.i2p.data.Base64;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Miscellaneous utility methods used by SAM protocol handlers. * Miscellaneous utility methods used by SAM protocol handlers.
@ -32,6 +33,7 @@ import net.i2p.util.Log;
public class SAMUtils { public class SAMUtils {
private final static Log _log = new Log(SAMUtils.class); private final static Log _log = new Log(SAMUtils.class);
private static I2PAppContext _context = new I2PAppContext();
/** /**
* Generate a random destination key * Generate a random destination key
@ -84,7 +86,7 @@ public class SAMUtils {
* @return the Destination for the specified hostname, or null if not found * @return the Destination for the specified hostname, or null if not found
*/ */
public static Destination lookupHost(String name, OutputStream pubKey) { public static Destination lookupHost(String name, OutputStream pubKey) {
NamingService ns = NamingService.getInstance(); NamingService ns = _context.namingService();
Destination dest = ns.lookup(name); Destination dest = ns.lookup(name);
if ((pubKey != null) && (dest != null)) { if ((pubKey != null) && (dest != null)) {

View File

@ -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;
/**
* <p>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.</p>
*
* 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. <pre>
* private static final Log _log = new Log(someClass.class);
* </pre>
* 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;
}
}
}

View File

@ -31,6 +31,7 @@ import net.i2p.util.Clock;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.LogManager; import net.i2p.util.LogManager;
import net.i2p.I2PAppContext;
/** /**
* ATalk - anonymous talk, demonstrating a trivial I2P usage scenario. * ATalk - anonymous talk, demonstrating a trivial I2P usage scenario.
@ -290,6 +291,7 @@ public class ATalk implements I2PSessionListener, Runnable {
/** driver */ /** driver */
public static void main(String args[]) { public static void main(String args[]) {
I2PAppContext context = new I2PAppContext();
if (args.length == 2) { if (args.length == 2) {
String myKeyFile = args[0]; String myKeyFile = args[0];
String myDestinationFile = args[1]; String myDestinationFile = args[1];
@ -309,9 +311,9 @@ public class ATalk implements I2PSessionListener, Runnable {
String peerDestFile = args[1]; String peerDestFile = args[1];
String shouldLog = args[2]; String shouldLog = args[2];
if (Boolean.TRUE.toString().equalsIgnoreCase(shouldLog)) if (Boolean.TRUE.toString().equalsIgnoreCase(shouldLog))
LogManager.getInstance().setDisplayOnScreen(true); context.logManager().setDisplayOnScreen(true);
else else
LogManager.getInstance().setDisplayOnScreen(false); context.logManager().setDisplayOnScreen(false);
String logFile = args[2]; String logFile = args[2];
Thread talkThread = new I2PThread(new ATalk(myKeyfile, peerDestFile)); Thread talkThread = new I2PThread(new ATalk(myKeyfile, peerDestFile));
talkThread.start(); talkThread.start();

View File

@ -11,6 +11,7 @@ package net.i2p.client;
import net.i2p.data.i2cp.DisconnectMessage; import net.i2p.data.i2cp.DisconnectMessage;
import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.I2PAppContext;
/** /**
* Handle I2CP disconnect messages from the router * Handle I2CP disconnect messages from the router
@ -18,8 +19,8 @@ import net.i2p.data.i2cp.I2CPMessage;
* @author jrandom * @author jrandom
*/ */
class DisconnectMessageHandler extends HandlerImpl { class DisconnectMessageHandler extends HandlerImpl {
public DisconnectMessageHandler() { public DisconnectMessageHandler(I2PAppContext context) {
super(DisconnectMessage.MESSAGE_TYPE); super(context, DisconnectMessage.MESSAGE_TYPE);
} }
public void handleMessage(I2CPMessage message, I2PSessionImpl session) { public void handleMessage(I2CPMessage message, I2PSessionImpl session) {

View File

@ -10,6 +10,7 @@ package net.i2p.client;
*/ */
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Base class for handling I2CP messages * Base class for handling I2CP messages
@ -19,8 +20,10 @@ import net.i2p.util.Log;
abstract class HandlerImpl implements I2CPMessageHandler { abstract class HandlerImpl implements I2CPMessageHandler {
protected Log _log; protected Log _log;
private int _type; private int _type;
protected I2PAppContext _context;
public HandlerImpl(int type) { public HandlerImpl(I2PAppContext context, int type) {
_context = context;
_type = type; _type = type;
_log = new Log(getClass()); _log = new Log(getClass());
} }

View File

@ -32,6 +32,7 @@ import net.i2p.data.i2cp.SendMessageMessage;
import net.i2p.data.i2cp.SessionConfig; import net.i2p.data.i2cp.SessionConfig;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Produce the various messages the session needs to send to the router. * Produce the various messages the session needs to send to the router.
@ -41,6 +42,11 @@ import net.i2p.util.RandomSource;
class I2CPMessageProducer { class I2CPMessageProducer {
private final static Log _log = new Log(I2CPMessageProducer.class); private final static Log _log = new Log(I2CPMessageProducer.class);
private final static RandomSource _rand = RandomSource.getInstance(); 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 * Send all the messages that a client needs to send to a router to establish
@ -102,7 +108,7 @@ class I2CPMessageProducer {
Payload data = new Payload(); Payload data = new Payload();
// randomize padding // randomize padding
int size = payload.length + RandomSource.getInstance().nextInt(1024); 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 // yes, in an intelligent component, newTags would be queued for confirmation along with key, and
// generateNewTags would only generate tags if necessary // generateNewTags would only generate tags if necessary

View File

@ -22,6 +22,7 @@ import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey; import net.i2p.data.PublicKey;
import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey; import net.i2p.data.SigningPublicKey;
import net.i2p.I2PAppContext;
/** /**
* Base client implementation * Base client implementation
@ -70,7 +71,13 @@ class I2PClientImpl implements I2PClient {
* *
*/ */
public I2PSession createSession(InputStream destKeyStream, Properties options) throws I2PSessionException { public I2PSession createSession(InputStream destKeyStream, Properties options) throws I2PSessionException {
//return new I2PSessionImpl(destKeyStream, options); // not thread safe return createSession(I2PAppContext.getGlobalContext(), destKeyStream, options);
return new I2PSessionImpl2(destKeyStream, options); // thread safe }
/**
* 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
} }
} }

View File

@ -19,6 +19,7 @@ import net.i2p.data.i2cp.RequestLeaseSetMessage;
import net.i2p.data.i2cp.SessionStatusMessage; import net.i2p.data.i2cp.SessionStatusMessage;
import net.i2p.data.i2cp.SetDateMessage; import net.i2p.data.i2cp.SetDateMessage;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Contains a map of message handlers that a session will want to use * Contains a map of message handlers that a session will want to use
@ -28,19 +29,19 @@ import net.i2p.util.Log;
class I2PClientMessageHandlerMap { class I2PClientMessageHandlerMap {
private final static Log _log = new Log(I2PClientMessageHandlerMap.class); private final static Log _log = new Log(I2PClientMessageHandlerMap.class);
/** map of message type id --> I2CPMessageHandler */ /** map of message type id --> I2CPMessageHandler */
private static Map _handlers; private Map _handlers;
static { public I2PClientMessageHandlerMap(I2PAppContext context) {
_handlers = new HashMap(); _handlers = new HashMap();
_handlers.put(new Integer(DisconnectMessage.MESSAGE_TYPE), new DisconnectMessageHandler()); _handlers.put(new Integer(DisconnectMessage.MESSAGE_TYPE), new DisconnectMessageHandler(context));
_handlers.put(new Integer(SessionStatusMessage.MESSAGE_TYPE), new SessionStatusMessageHandler()); _handlers.put(new Integer(SessionStatusMessage.MESSAGE_TYPE), new SessionStatusMessageHandler(context));
_handlers.put(new Integer(RequestLeaseSetMessage.MESSAGE_TYPE), new RequestLeaseSetMessageHandler()); _handlers.put(new Integer(RequestLeaseSetMessage.MESSAGE_TYPE), new RequestLeaseSetMessageHandler(context));
_handlers.put(new Integer(MessagePayloadMessage.MESSAGE_TYPE), new MessagePayloadMessageHandler()); _handlers.put(new Integer(MessagePayloadMessage.MESSAGE_TYPE), new MessagePayloadMessageHandler(context));
_handlers.put(new Integer(MessageStatusMessage.MESSAGE_TYPE), new MessageStatusMessageHandler()); _handlers.put(new Integer(MessageStatusMessage.MESSAGE_TYPE), new MessageStatusMessageHandler(context));
_handlers.put(new Integer(SetDateMessage.MESSAGE_TYPE), new SetDateMessageHandler()); _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)); I2CPMessageHandler handler = (I2CPMessageHandler) _handlers.get(new Integer(messageTypeId));
return handler; return handler;
} }

View File

@ -39,6 +39,7 @@ import net.i2p.data.i2cp.SessionId;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Implementation of an I2P session running over TCP. This class is NOT thread safe - * 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 * @author jrandom
*/ */
abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener { abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener {
private final static Log _log = new Log(I2PSessionImpl.class); private Log _log;
/** who we are */ /** who we are */
private Destination _myDestination; private Destination _myDestination;
/** private key for decryption */ /** private key for decryption */
@ -80,6 +81,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
/** map of integer --> MessagePayloadMessage */ /** map of integer --> MessagePayloadMessage */
Map _availableMessages; 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 */ /** MessageStatusMessage status from the most recent send that hasn't been consumed */
private List _receivedStatus; private List _receivedStatus;
private int _totalReconnectAttempts; private int _totalReconnectAttempts;
@ -108,9 +114,12 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* *
* @throws I2PSessionException if there is a problem loading the private keys or * @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; _closed = true;
_producer = new I2CPMessageProducer(); _producer = new I2CPMessageProducer(context);
_availableMessages = new HashMap(); _availableMessages = new HashMap();
try { try {
readDestination(destKeyStream); readDestination(destKeyStream);
@ -145,7 +154,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
} }
} }
private static Properties filter(Properties options) { private Properties filter(Properties options) {
Properties rv = new Properties(); Properties rv = new Properties();
for (Iterator iter = options.keySet().iterator(); iter.hasNext();) { for (Iterator iter = options.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next(); String key = (String) iter.next();
@ -212,7 +221,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
*/ */
public void connect() throws I2PSessionException { public void connect() throws I2PSessionException {
_closed = false; _closed = false;
long startConnect = Clock.getInstance().now(); long startConnect = _context.clock().now();
try { try {
if (_log.shouldLog(Log.DEBUG)) _log.debug("connect begin to " + _hostname + ":" + _portNum); if (_log.shouldLog(Log.DEBUG)) _log.debug("connect begin to " + _hostname + ":" + _portNum);
_socket = new Socket(_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)) if (_log.shouldLog(Log.INFO))
_log.info("Lease set created with inbound tunnels after " _log.info("Lease set created with inbound tunnels after "
+ (connected - startConnect) + (connected - startConnect)
@ -339,7 +348,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
* *
*/ */
public void messageReceived(I2CPMessageReader reader, I2CPMessage message) { public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
I2CPMessageHandler handler = I2PClientMessageHandlerMap.getHandler(message.getType()); I2CPMessageHandler handler = _handlerMap.getHandler(message.getType());
if (handler == null) { if (handler == null) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Unknown message or unhandleable message received: type = " _log.warn("Unknown message or unhandleable message received: type = "

View File

@ -26,6 +26,7 @@ import net.i2p.data.i2cp.MessageStatusMessage;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Thread safe implementation of an I2P session running over TCP. * Thread safe implementation of an I2P session running over TCP.
@ -33,7 +34,7 @@ import net.i2p.util.RandomSource;
* @author jrandom * @author jrandom
*/ */
class I2PSessionImpl2 extends I2PSessionImpl { 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 */ /** set of MessageState objects, representing all of the messages in the process of being sent */
private Set _sendingStates; private Set _sendingStates;
@ -48,8 +49,9 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* *
* @throws I2PSessionException if there is a problem loading the private keys or * @throws I2PSessionException if there is a problem loading the private keys or
*/ */
public I2PSessionImpl2(InputStream destKeyStream, Properties options) throws I2PSessionException { public I2PSessionImpl2(I2PAppContext ctx, InputStream destKeyStream, Properties options) throws I2PSessionException {
super(destKeyStream, options); super(ctx, destKeyStream, options);
_log = ctx.logManager().getLog(I2PSessionImpl2.class);
_sendingStates = new HashSet(32); _sendingStates = new HashSet(32);
} }
@ -95,22 +97,22 @@ class I2PSessionImpl2 extends I2PSessionImpl {
private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent) private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent)
throws I2PSessionException { throws I2PSessionException {
SessionKey key = SessionKeyManager.getInstance().getCurrentKey(dest.getPublicKey()); SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey());
if (key == null) key = SessionKeyManager.getInstance().createSession(dest.getPublicKey()); if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey());
SessionTag tag = SessionKeyManager.getInstance().consumeNextAvailableTag(dest.getPublicKey(), key); SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key);
Set sentTags = null; Set sentTags = null;
if (SessionKeyManager.getInstance().getAvailableTags(dest.getPublicKey(), key) < 10) { if (_context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key) < 10) {
sentTags = createNewTags(50); 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 // if we have > 10 tags, but they expire in under 30 seconds, we want more
sentTags = createNewTags(50); sentTags = createNewTags(50);
if (_log.shouldLog(Log.DEBUG)) _log.debug("Tags are almost expired, adding 50 new ones"); if (_log.shouldLog(Log.DEBUG)) _log.debug("Tags are almost expired, adding 50 new ones");
} }
SessionKey newKey = null; SessionKey newKey = null;
if (false) // rekey 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); MessageState state = new MessageState(nonce);
state.setKey(key); state.setKey(key);
state.setTags(sentTags); state.setTags(sentTags);
@ -137,7 +139,8 @@ class I2PSessionImpl2 extends I2PSessionImpl {
_log.debug("Adding sending state " + state.getMessageId() + " / " _log.debug("Adding sending state " + state.getMessageId() + " / "
+ state.getNonce()); + state.getNonce());
_producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey); _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) { synchronized (_sendingStates) {
_sendingStates.remove(state); _sendingStates.remove(state);
} }
@ -163,22 +166,22 @@ class I2PSessionImpl2 extends I2PSessionImpl {
private boolean sendGuaranteed(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent) private boolean sendGuaranteed(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent)
throws I2PSessionException { throws I2PSessionException {
SessionKey key = SessionKeyManager.getInstance().getCurrentKey(dest.getPublicKey()); SessionKey key = _context.sessionKeyManager().getCurrentKey(dest.getPublicKey());
if (key == null) key = SessionKeyManager.getInstance().createSession(dest.getPublicKey()); if (key == null) key = _context.sessionKeyManager().createSession(dest.getPublicKey());
SessionTag tag = SessionKeyManager.getInstance().consumeNextAvailableTag(dest.getPublicKey(), key); SessionTag tag = _context.sessionKeyManager().consumeNextAvailableTag(dest.getPublicKey(), key);
Set sentTags = null; Set sentTags = null;
if (SessionKeyManager.getInstance().getAvailableTags(dest.getPublicKey(), key) < 10) { if (_context.sessionKeyManager().getAvailableTags(dest.getPublicKey(), key) < 10) {
sentTags = createNewTags(50); 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 // if we have > 10 tags, but they expire in under 30 seconds, we want more
sentTags = createNewTags(50); sentTags = createNewTags(50);
if (_log.shouldLog(Log.DEBUG)) _log.debug("Tags are almost expired, adding 50 new ones"); if (_log.shouldLog(Log.DEBUG)) _log.debug("Tags are almost expired, adding 50 new ones");
} }
SessionKey newKey = null; SessionKey newKey = null;
if (false) // rekey 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); MessageState state = new MessageState(nonce);
state.setKey(key); state.setKey(key);
state.setTags(sentTags); state.setTags(sentTags);
@ -206,9 +209,11 @@ class I2PSessionImpl2 extends I2PSessionImpl {
+ state.getNonce()); + state.getNonce());
_producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey); _producer.sendMessage(this, dest, nonce, payload, tag, key, sentTags, newKey);
if (isGuaranteed()) 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 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) { synchronized (_sendingStates) {
_sendingStates.remove(state); _sendingStates.remove(state);
} }
@ -250,9 +255,9 @@ class I2PSessionImpl2 extends I2PSessionImpl {
+ state.getTags()); + state.getTags());
if ((state.getTags() != null) && (state.getTags().size() > 0)) { if ((state.getTags() != null) && (state.getTags().size() > 0)) {
if (state.getNewKey() == null) 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 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)) if (_log.shouldLog(Log.INFO))
_log.info("nack tags for msgId " + state.getMessageId() + " / " + state.getNonce() _log.info("nack tags for msgId " + state.getMessageId() + " / " + state.getNonce()
+ " key = " + state.getKey()); + " key = " + state.getKey());
SessionKeyManager.getInstance().failTags(state.getTo().getPublicKey()); _context.sessionKeyManager().failTags(state.getTo().getPublicKey());
} }
public void receiveStatus(int msgId, long nonce, int status) { public void receiveStatus(int msgId, long nonce, int status) {

View File

@ -16,6 +16,7 @@ import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.MessageId; import net.i2p.data.i2cp.MessageId;
import net.i2p.data.i2cp.MessagePayloadMessage; import net.i2p.data.i2cp.MessagePayloadMessage;
import net.i2p.data.i2cp.ReceiveMessageEndMessage; import net.i2p.data.i2cp.ReceiveMessageEndMessage;
import net.i2p.I2PAppContext;
/** /**
* Handle I2CP MessagePayloadMessages from the router delivering the contents * Handle I2CP MessagePayloadMessages from the router delivering the contents
@ -25,8 +26,8 @@ import net.i2p.data.i2cp.ReceiveMessageEndMessage;
* @author jrandom * @author jrandom
*/ */
class MessagePayloadMessageHandler extends HandlerImpl { class MessagePayloadMessageHandler extends HandlerImpl {
public MessagePayloadMessageHandler() { public MessagePayloadMessageHandler(I2PAppContext context) {
super(MessagePayloadMessage.MESSAGE_TYPE); super(context, MessagePayloadMessage.MESSAGE_TYPE);
} }
public void handleMessage(I2CPMessage message, I2PSessionImpl session) { public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
@ -53,7 +54,7 @@ class MessagePayloadMessageHandler extends HandlerImpl {
*/ */
private Payload decryptPayload(MessagePayloadMessage msg, I2PSessionImpl session) throws DataFormatException { private Payload decryptPayload(MessagePayloadMessage msg, I2PSessionImpl session) throws DataFormatException {
Payload payload = msg.getPayload(); Payload payload = msg.getPayload();
byte[] data = ElGamalAESEngine.decrypt(payload.getEncryptedData(), session.getDecryptionKey()); byte[] data = _context.elGamalAESEngine().decrypt(payload.getEncryptedData(), session.getDecryptionKey());
if (data == null) { if (data == null) {
_log _log
.error("Error decrypting the payload to public key " .error("Error decrypting the payload to public key "

View File

@ -12,6 +12,7 @@ package net.i2p.client;
import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.MessageStatusMessage; import net.i2p.data.i2cp.MessageStatusMessage;
import net.i2p.data.i2cp.ReceiveMessageBeginMessage; import net.i2p.data.i2cp.ReceiveMessageBeginMessage;
import net.i2p.I2PAppContext;
/** /**
* Handle I2CP MessageStatusMessages from the router. This currently only takes * Handle I2CP MessageStatusMessages from the router. This currently only takes
@ -21,8 +22,8 @@ import net.i2p.data.i2cp.ReceiveMessageBeginMessage;
* @author jrandom * @author jrandom
*/ */
class MessageStatusMessageHandler extends HandlerImpl { class MessageStatusMessageHandler extends HandlerImpl {
public MessageStatusMessageHandler() { public MessageStatusMessageHandler(I2PAppContext context) {
super(MessageStatusMessage.MESSAGE_TYPE); super(context, MessageStatusMessage.MESSAGE_TYPE);
} }
public void handleMessage(I2CPMessage message, I2PSessionImpl session) { public void handleMessage(I2CPMessage message, I2PSessionImpl session) {

View File

@ -25,6 +25,7 @@ import net.i2p.data.SigningPublicKey;
import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.RequestLeaseSetMessage; import net.i2p.data.i2cp.RequestLeaseSetMessage;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Handle I2CP RequestLeaseSetMessage from the router by granting all leases * 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 final static Log _log = new Log(RequestLeaseSetMessageHandler.class);
private Map _existingLeaseSets; private Map _existingLeaseSets;
public RequestLeaseSetMessageHandler() { public RequestLeaseSetMessageHandler(I2PAppContext context) {
super(RequestLeaseSetMessage.MESSAGE_TYPE); super(context, RequestLeaseSetMessage.MESSAGE_TYPE);
_existingLeaseSets = new HashMap(32); _existingLeaseSets = new HashMap(32);
} }

View File

@ -11,6 +11,7 @@ package net.i2p.client;
import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.SessionStatusMessage; import net.i2p.data.i2cp.SessionStatusMessage;
import net.i2p.I2PAppContext;
/** /**
* Handle I2CP SessionStatusMessagese from the router, updating the session as * Handle I2CP SessionStatusMessagese from the router, updating the session as
@ -19,8 +20,8 @@ import net.i2p.data.i2cp.SessionStatusMessage;
* @author jrandom * @author jrandom
*/ */
class SessionStatusMessageHandler extends HandlerImpl { class SessionStatusMessageHandler extends HandlerImpl {
public SessionStatusMessageHandler() { public SessionStatusMessageHandler(I2PAppContext context) {
super(SessionStatusMessage.MESSAGE_TYPE); super(context, SessionStatusMessage.MESSAGE_TYPE);
} }
public void handleMessage(I2CPMessage message, I2PSessionImpl session) { public void handleMessage(I2CPMessage message, I2PSessionImpl session) {

View File

@ -12,6 +12,7 @@ package net.i2p.client;
import net.i2p.data.i2cp.I2CPMessage; import net.i2p.data.i2cp.I2CPMessage;
import net.i2p.data.i2cp.SetDateMessage; import net.i2p.data.i2cp.SetDateMessage;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.I2PAppContext;
/** /**
* Handle I2CP time messages from the router * Handle I2CP time messages from the router
@ -19,8 +20,8 @@ import net.i2p.util.Clock;
* @author jrandom * @author jrandom
*/ */
class SetDateMessageHandler extends HandlerImpl { class SetDateMessageHandler extends HandlerImpl {
public SetDateMessageHandler() { public SetDateMessageHandler(I2PAppContext ctx) {
super(SetDateMessage.MESSAGE_TYPE); super(ctx, SetDateMessage.MESSAGE_TYPE);
} }
public void handleMessage(I2CPMessage message, I2PSessionImpl session) { public void handleMessage(I2CPMessage message, I2PSessionImpl session) {

View File

@ -8,11 +8,21 @@
package net.i2p.client.naming; package net.i2p.client.naming;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.I2PAppContext;
/** /**
* A Dummy naming service that can only handle base64 destinations. * A Dummy naming service that can only handle base64 destinations.
*/ */
class DummyNamingService extends NamingService { 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) { public Destination lookup(String hostname) {
return lookupBase64(hostname); return lookupBase64(hostname);
} }

View File

@ -14,12 +14,22 @@ import java.util.Properties;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* A naming service based on the "hosts.txt" file. * A naming service based on the "hosts.txt" file.
*/ */
public class HostsTxtNamingService extends NamingService { 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 * If this system property is specified, the tunnel will read the
* given file for hostname=destKey values when resolving names * 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 // Try to look it up in hosts.txt
// Reload file each time to catch changes. // Reload file each time to catch changes.
// (and it's easier :P // (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(); Properties hosts = new Properties();
FileInputStream fis = null; FileInputStream fis = null;
try { try {

View File

@ -10,6 +10,9 @@ package net.i2p.client.naming;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.Destination; import net.i2p.data.Destination;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
import java.lang.reflect.Constructor;
/** /**
* Naming services create a subclass of this class. * Naming services create a subclass of this class.
@ -17,10 +20,23 @@ import net.i2p.util.Log;
public abstract class NamingService { public abstract class NamingService {
private final static Log _log = new Log(NamingService.class); 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 PROP_IMPL = "i2p.naming.impl";
private static final String DEFAULT_IMPL = "net.i2p.client.naming.HostsTxtNamingService"; 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. * Look up a host name.
* @return the Destination for this host name, or * @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 * Get a naming service instance. This method ensures that there
* will be only one naming service instance (singleton) as well as * will be only one naming service instance (singleton) as well as
* choose the implementation from the "i2p.naming.impl" system * choose the implementation from the "i2p.naming.impl" system
* property. * property.
*/ */
public static synchronized NamingService getInstance() { public static final synchronized NamingService createInstance(I2PAppContext context) {
if (instance == null) { NamingService instance = null;
String impl = System.getProperty(PROP_IMPL, DEFAULT_IMPL); String impl = context.getProperty(PROP_IMPL, DEFAULT_IMPL);
try { try {
instance = (NamingService) Class.forName(impl).newInstance(); Class cls = Class.forName(impl);
Constructor con = cls.getConstructor(new Class[] { I2PAppContext.class });
instance = (NamingService)con.newInstance(new Object[] { context });
} catch (Exception ex) { } catch (Exception ex) {
_log.error("Cannot loadNaming service implementation", ex); _log.error("Cannot loadNaming service implementation", ex);
instance = new DummyNamingService(); // fallback instance = new DummyNamingService(context); // fallback
}
} }
return instance; return instance;
} }

View File

@ -19,24 +19,18 @@ import net.i2p.data.Hash;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; 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 { public class AESEngine {
private final static Log _log = new Log(AESEngine.class); private Log _log;
private static AESEngine _engine; private I2PAppContext _context;
static { public AESEngine(I2PAppContext ctx) {
if ("off".equals(System.getProperty("i2p.encryption", "on"))) _context = ctx;
_engine = new AESEngine(); _log = _context.logManager().getLog(AESEngine.class);
else
_engine = new CryptixAESEngine();
}
public static AESEngine getInstance() {
return _engine;
} }
/** Encrypt the payload with the session key /** Encrypt the payload with the session key
@ -59,13 +53,13 @@ public class AESEngine {
if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null; if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null;
ByteArrayOutputStream baos = new ByteArrayOutputStream(paddedSize + 64); ByteArrayOutputStream baos = new ByteArrayOutputStream(paddedSize + 64);
Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); Hash h = _context.sha().calculateHash(sessionKey.getData());
try { try {
h.writeBytes(baos); h.writeBytes(baos);
DataHelper.writeLong(baos, 4, payload.length); DataHelper.writeLong(baos, 4, payload.length);
baos.write(payload); baos.write(payload);
byte tv[] = baos.toByteArray(); byte tv[] = baos.toByteArray();
baos.write(ElGamalAESEngine.getPadding(tv.length, paddedSize)); baos.write(ElGamalAESEngine.getPadding(_context, tv.length, paddedSize));
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error writing data", ioe); _log.error("Error writing data", ioe);
return null; return null;
@ -85,7 +79,7 @@ public class AESEngine {
return null; return null;
} }
ByteArrayInputStream bais = new ByteArrayInputStream(decr); ByteArrayInputStream bais = new ByteArrayInputStream(decr);
Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); Hash h = _context.sha().calculateHash(sessionKey.getData());
try { try {
Hash rh = new Hash(); Hash rh = new Hash();
rh.readBytes(bais); rh.readBytes(bais);
@ -127,20 +121,21 @@ public class AESEngine {
} }
public static void main(String args[]) { 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]; byte iv[] = new byte[16];
RandomSource.getInstance().nextBytes(iv); RandomSource.getInstance().nextBytes(iv);
byte sbuf[] = new byte[16]; byte sbuf[] = new byte[16];
RandomSource.getInstance().nextBytes(sbuf); RandomSource.getInstance().nextBytes(sbuf);
byte se[] = AESEngine.getInstance().encrypt(sbuf, key, iv); byte se[] = ctx.AESEngine().encrypt(sbuf, key, iv);
byte sd[] = AESEngine.getInstance().decrypt(se, key, iv); byte sd[] = ctx.AESEngine().decrypt(se, key, iv);
_log.debug("Short test: " + DataHelper.eq(sd, sbuf)); ctx.logManager().getLog(AESEngine.class).debug("Short test: " + DataHelper.eq(sd, sbuf));
byte lbuf[] = new byte[1024]; byte lbuf[] = new byte[1024];
RandomSource.getInstance().nextBytes(sbuf); RandomSource.getInstance().nextBytes(sbuf);
byte le[] = AESEngine.getInstance().safeEncrypt(lbuf, key, iv, 2048); byte le[] = ctx.AESEngine().safeEncrypt(lbuf, key, iv, 2048);
byte ld[] = AESEngine.getInstance().safeDecrypt(le, key, iv); byte ld[] = ctx.AESEngine().safeDecrypt(le, key, iv);
_log.debug("Long test: " + DataHelper.eq(ld, lbuf)); ctx.logManager().getLog(AESEngine.class).debug("Long test: " + DataHelper.eq(ld, lbuf));
} }
} }

View File

@ -24,6 +24,7 @@ import net.i2p.data.SessionKey;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* This reads an underlying stream as written by AESOutputStream - AES256 encrypted * 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 { public class AESInputStream extends FilterInputStream {
private final static Log _log = new Log(AESInputStream.class); private Log _log;
private final static CryptixAESEngine _engine = new CryptixAESEngine(); private I2PAppContext _context;
private SessionKey _key; private SessionKey _key;
private byte[] _lastBlock; private byte[] _lastBlock;
private boolean _eofFound; private boolean _eofFound;
@ -52,8 +53,10 @@ public class AESInputStream extends FilterInputStream {
private final static int READ_SIZE = BLOCK_SIZE; private final static int READ_SIZE = BLOCK_SIZE;
private final static int DECRYPT_SIZE = BLOCK_SIZE - 1; 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); super(source);
_context = context;
_log = context.logManager().getLog(AESInputStream.class);
_key = key; _key = key;
_lastBlock = new byte[BLOCK_SIZE]; _lastBlock = new byte[BLOCK_SIZE];
System.arraycopy(iv, 0, _lastBlock, 0, 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]; byte block[] = new byte[BLOCK_SIZE];
for (int i = 0; i < numBlocks; i++) { for (int i = 0; i < numBlocks; i++) {
System.arraycopy(encrypted, i * BLOCK_SIZE, block, 0, BLOCK_SIZE); System.arraycopy(encrypted, i * BLOCK_SIZE, block, 0, BLOCK_SIZE);
byte decrypted[] = _engine.decrypt(block, _key, _lastBlock); byte decrypted[] = _context.AESEngine().decrypt(block, _key, _lastBlock);
byte data[] = CryptixAESEngine.xor(decrypted, _lastBlock); byte data[] = DataHelper.xor(decrypted, _lastBlock);
int cleaned[] = stripPadding(data); int cleaned[] = stripPadding(data);
for (int j = 0; j < cleaned.length; j++) { for (int j = 0; j < cleaned.length; j++) {
if (((int) cleaned[j]) <= 0) { if (((int) cleaned[j]) <= 0) {
@ -297,6 +300,8 @@ public class AESInputStream extends FilterInputStream {
* Test AESOutputStream/AESInputStream * Test AESOutputStream/AESInputStream
*/ */
public static void main(String args[]) { public static void main(String args[]) {
I2PAppContext ctx = new I2PAppContext();
Log log = ctx.logManager().getLog(AESInputStream.class);
byte orig[] = new byte[1024 * 32]; byte orig[] = new byte[1024 * 32];
RandomSource.getInstance().nextBytes(orig); RandomSource.getInstance().nextBytes(orig);
//byte orig[] = "you are my sunshine, my only sunshine".getBytes(); //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(); byte iv[] = "there once was a".getBytes();
for (int i = 0; i < 20; i++) { 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]; orig = new byte[20];
RandomSource.getInstance().nextBytes(orig); RandomSource.getInstance().nextBytes(orig);
for (int i = 0; i < 20; i++) { 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]; orig = new byte[3];
RandomSource.getInstance().nextBytes(orig); RandomSource.getInstance().nextBytes(orig);
for (int i = 0; i < 20; i++) { 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]; orig = new byte[0];
RandomSource.getInstance().nextBytes(orig); RandomSource.getInstance().nextBytes(orig);
for (int i = 0; i < 20; i++) { 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]; orig = new byte[32];
RandomSource.getInstance().nextBytes(orig); 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 { try {
Thread.sleep(30 * 1000); 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 { try {
long start = Clock.getInstance().now(); long start = Clock.getInstance().now();
ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); ByteArrayOutputStream origStream = new ByteArrayOutputStream(512);
AESOutputStream out = new AESOutputStream(origStream, key, iv); AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv);
out.write(orig); out.write(orig);
out.close(); out.close();
@ -357,7 +363,7 @@ public class AESInputStream extends FilterInputStream {
long endE = Clock.getInstance().now(); long endE = Clock.getInstance().now();
ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encrypted); 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); ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
byte buf[] = new byte[1024 * 32]; byte buf[] = new byte[1024 * 32];
int read = DataHelper.read(in, buf); int read = DataHelper.read(in, buf);
@ -370,65 +376,66 @@ public class AESInputStream extends FilterInputStream {
Hash newHash = SHA256Generator.getInstance().calculateHash(fin); Hash newHash = SHA256Generator.getInstance().calculateHash(fin);
boolean eq = origHash.equals(newHash); boolean eq = origHash.equals(newHash);
if (eq) if (eq)
_log.info("Equal hashes. hash: " + origHash); log.info("Equal hashes. hash: " + origHash);
else 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); boolean ok = DataHelper.eq(orig, fin);
_log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); 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 D(E(" + orig.length + ")): " + (end - start) + "ms");
_log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms");
_log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms");
} catch (Throwable t) { } catch (Throwable t) {
_log.error("ERROR transferring", t); log.error("ERROR transferring", t);
} }
//try { Thread.sleep(5000); } catch (Throwable 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 { try {
long start = Clock.getInstance().now(); long start = Clock.getInstance().now();
ByteArrayOutputStream origStream = new ByteArrayOutputStream(512); ByteArrayOutputStream origStream = new ByteArrayOutputStream(512);
AESOutputStream out = new AESOutputStream(origStream, key, iv); AESOutputStream out = new AESOutputStream(ctx, origStream, key, iv);
out.write(orig); out.write(orig);
out.close(); out.close();
byte encrypted[] = origStream.toByteArray(); byte encrypted[] = origStream.toByteArray();
long endE = Clock.getInstance().now(); long endE = Clock.getInstance().now();
_log.info("Encrypted segment length: " + encrypted.length); log.info("Encrypted segment length: " + encrypted.length);
byte encryptedSegment[] = new byte[40]; byte encryptedSegment[] = new byte[40];
System.arraycopy(encrypted, 0, encryptedSegment, 0, 40); System.arraycopy(encrypted, 0, encryptedSegment, 0, 40);
ByteArrayInputStream encryptedStream = new ByteArrayInputStream(encryptedSegment); 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); ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
byte buf[] = new byte[1024 * 32]; byte buf[] = new byte[1024 * 32];
int read = DataHelper.read(in, buf); int read = DataHelper.read(in, buf);
int remaining = in.remainingBytes(); int remaining = in.remainingBytes();
int readyBytes = in.readyBytes(); int readyBytes = in.readyBytes();
_log.info("Read: " + read); log.info("Read: " + read);
if (read > 0) baos.write(buf, 0, read); if (read > 0) baos.write(buf, 0, read);
in.close(); in.close();
byte fin[] = baos.toByteArray(); 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(); long end = Clock.getInstance().now();
Hash origHash = SHA256Generator.getInstance().calculateHash(orig); Hash origHash = SHA256Generator.getInstance().calculateHash(orig);
Hash newHash = SHA256Generator.getInstance().calculateHash(fin); Hash newHash = SHA256Generator.getInstance().calculateHash(fin);
boolean eq = origHash.equals(newHash); boolean eq = origHash.equals(newHash);
if (eq) if (eq)
_log.info("Equal hashes. hash: " + origHash); log.info("Equal hashes. hash: " + origHash);
else 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); boolean ok = DataHelper.eq(orig, fin);
_log.debug("EQ data? " + ok + " origLen: " + orig.length + " fin.length: " + fin.length); 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 D(E(" + orig.length + ")): " + (end - start) + "ms");
_log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms"); log.debug("Time to E(" + orig.length + "): " + (endE - start) + "ms");
_log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms"); log.debug("Time to D(" + orig.length + "): " + (end - endE) + "ms");
} catch (Throwable t) { } catch (Throwable t) {
_log.error("ERROR transferring", t); log.error("ERROR transferring", t);
} }
//try { Thread.sleep(5000); } catch (Throwable t) {} //try { Thread.sleep(5000); } catch (Throwable t) {}
} }

View File

@ -16,7 +16,9 @@ import java.io.OutputStream;
import java.util.Arrays; import java.util.Arrays;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.data.DataHelper;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* This writes everything as CBC with PKCS#5 padding, but each block is padded * 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 { public class AESOutputStream extends FilterOutputStream {
private final static CryptixAESEngine _engine = new CryptixAESEngine(); private Log _log;
private final static Log _log = new Log(AESOutputStream.class); private I2PAppContext _context;
private SessionKey _key; private SessionKey _key;
private byte[] _lastBlock; private byte[] _lastBlock;
private ByteArrayOutputStream _inBuf; 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 BLOCK_SIZE = CryptixRijndael_Algorithm._BLOCK_SIZE;
private final static int MAX_BUF = 256; 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); super(source);
_context = context;
_log = context.logManager().getLog(AESOutputStream.class);
_key = key; _key = key;
_lastBlock = new byte[BLOCK_SIZE]; _lastBlock = new byte[BLOCK_SIZE];
System.arraycopy(iv, 0, _lastBlock, 0, 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 block[BLOCK_SIZE - 1] = 0x01; // the padding byte for "full" blocks
for (int i = 0; i < numBlocks; i++) { for (int i = 0; i < numBlocks; i++) {
System.arraycopy(src, i * 15, block, 0, 15); System.arraycopy(src, i * 15, block, 0, 15);
byte data[] = _engine.xor(block, _lastBlock); byte data[] = DataHelper.xor(block, _lastBlock);
byte encrypted[] = _engine.encrypt(data, _key, _lastBlock); byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock);
_cumulativeWritten += encrypted.length; _cumulativeWritten += encrypted.length;
out.write(encrypted); out.write(encrypted);
System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); 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; int paddingBytes = BLOCK_SIZE - remainingBytes;
System.arraycopy(src, numBlocks * 15, block, 0, remainingBytes); System.arraycopy(src, numBlocks * 15, block, 0, remainingBytes);
Arrays.fill(block, remainingBytes, BLOCK_SIZE, (byte) paddingBytes); Arrays.fill(block, remainingBytes, BLOCK_SIZE, (byte) paddingBytes);
byte data[] = _engine.xor(block, _lastBlock); byte data[] = DataHelper.xor(block, _lastBlock);
byte encrypted[] = _engine.encrypt(data, _key, _lastBlock); byte encrypted[] = _context.AESEngine().encrypt(data, _key, _lastBlock);
out.write(encrypted); out.write(encrypted);
System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE); System.arraycopy(encrypted, encrypted.length - BLOCK_SIZE, _lastBlock, 0, BLOCK_SIZE);
_cumulativePadding += paddingBytes; _cumulativePadding += paddingBytes;

View File

@ -13,6 +13,7 @@ import java.security.InvalidKeyException;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Wrapper for AES cypher operation using Cryptix's Rijndael implementation. Implements * Wrapper for AES cypher operation using Cryptix's Rijndael implementation. Implements
@ -23,11 +24,16 @@ import net.i2p.util.Log;
* @author jrandom, thecrypto * @author jrandom, thecrypto
*/ */
public class CryptixAESEngine extends AESEngine { 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 CryptixRijndael_Algorithm _algo = new CryptixRijndael_Algorithm();
private final static boolean USE_FAKE_CRYPTO = false; private final static boolean USE_FAKE_CRYPTO = false;
private final static byte FAKE_KEY = 0x2A; 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[]) { public byte[] encrypt(byte payload[], SessionKey sessionKey, byte initializationVector[]) {
if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null) if ((initializationVector == null) || (payload == null) || (payload.length <= 0) || (sessionKey == null)
|| (initializationVector.length != 16)) return null; || (initializationVector.length != 16)) return null;
@ -116,7 +122,7 @@ public class CryptixAESEngine extends AESEngine {
* @param sessionKey private esession key to encrypt to * @param sessionKey private esession key to encrypt to
* @return encrypted data * @return encrypted data
*/ */
final static byte[] encrypt(byte payload[], SessionKey sessionKey) { final byte[] encrypt(byte payload[], SessionKey sessionKey) {
try { try {
Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16); Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16);
byte rv[] = new byte[payload.length]; byte rv[] = new byte[payload.length];
@ -133,7 +139,7 @@ public class CryptixAESEngine extends AESEngine {
* @param sessionKey private session key * @param sessionKey private session key
* @return unencrypted data * @return unencrypted data
*/ */
final static byte[] decrypt(byte payload[], SessionKey sessionKey) { final byte[] decrypt(byte payload[], SessionKey sessionKey) {
try { try {
Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16); Object key = CryptixRijndael_Algorithm.makeKey(sessionKey.getData(), 16);
byte rv[] = new byte[payload.length]; byte rv[] = new byte[payload.length];

View File

@ -20,6 +20,7 @@ import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Generate a new session key through a diffie hellman exchange. This uses the * 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"; public final static String DEFAULT_DH_PRECALC_DELAY = "1000";
static { static {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
try { 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; MIN_NUM_BUILDERS = val;
} catch (Throwable t) { } catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_DH_PRECALC_MIN); int val = Integer.parseInt(DEFAULT_DH_PRECALC_MIN);
MIN_NUM_BUILDERS = val; MIN_NUM_BUILDERS = val;
} }
try { 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; MAX_NUM_BUILDERS = val;
} catch (Throwable t) { } catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_DH_PRECALC_MAX); int val = Integer.parseInt(DEFAULT_DH_PRECALC_MAX);
MAX_NUM_BUILDERS = val; MAX_NUM_BUILDERS = val;
} }
try { 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; CALC_DELAY = val;
} catch (Throwable t) { } catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_DH_PRECALC_DELAY); int val = Integer.parseInt(DEFAULT_DH_PRECALC_DELAY);
@ -266,6 +268,7 @@ public class DHSessionKeyBuilder {
Thread.sleep(20 * 1000); Thread.sleep(20 * 1000);
} catch (InterruptedException ie) { } catch (InterruptedException ie) {
} }
I2PAppContext ctx = new I2PAppContext();
_log.debug("\n\n\n\nBegin test\n"); _log.debug("\n\n\n\nBegin test\n");
long negTime = 0; long negTime = 0;
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
@ -289,8 +292,8 @@ public class DHSessionKeyBuilder {
byte iv[] = new byte[16]; byte iv[] = new byte[16];
RandomSource.getInstance().nextBytes(iv); RandomSource.getInstance().nextBytes(iv);
String origVal = "1234567890123456"; // 16 bytes max using AESEngine String origVal = "1234567890123456"; // 16 bytes max using AESEngine
byte enc[] = AESEngine.getInstance().encrypt(origVal.getBytes(), key1, iv); byte enc[] = ctx.AESEngine().encrypt(origVal.getBytes(), key1, iv);
byte dec[] = AESEngine.getInstance().decrypt(enc, key2, iv); byte dec[] = ctx.AESEngine().decrypt(enc, key2, iv);
String tranVal = new String(dec); String tranVal = new String(dec);
if (origVal.equals(tranVal)) if (origVal.equals(tranVal))
_log.debug("**Success: D(E(val)) == val"); _log.debug("**Success: D(E(val)) == val");

View File

@ -39,17 +39,22 @@ import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
public class DSAEngine { public class DSAEngine {
private final static Log _log = new Log(DSAEngine.class); private Log _log;
private static DSAEngine _instance = new DSAEngine(); private I2PAppContext _context;
public DSAEngine(I2PAppContext context) {
_log = context.logManager().getLog(DSAEngine.class);
_context = context;
}
public static DSAEngine getInstance() { public static DSAEngine getInstance() {
return _instance; return I2PAppContext.getGlobalContext().dsa();
} }
public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) { public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) {
long start = Clock.getInstance().now(); long start = _context.clock().now();
byte[] sigbytes = signature.getData(); byte[] sigbytes = signature.getData();
byte rbytes[] = new byte[20]; byte rbytes[] = new byte[20];
@ -65,22 +70,20 @@ public class DSAEngine {
BigInteger r = new NativeBigInteger(1, rbytes); BigInteger r = new NativeBigInteger(1, rbytes);
BigInteger y = new NativeBigInteger(1, verifyingKey.getData()); BigInteger y = new NativeBigInteger(1, verifyingKey.getData());
BigInteger w = s.modInverse(CryptoConstants.dsaq); BigInteger w = s.modInverse(CryptoConstants.dsaq);
BigInteger u1 = ((new NativeBigInteger(1, calculateHash(signedData).getData())).multiply(w)) byte data[] = calculateHash(signedData).getData();
.mod(CryptoConstants.dsaq); NativeBigInteger bi = new NativeBigInteger(1, data);
BigInteger u1 = bi.multiply(w).mod(CryptoConstants.dsaq);
BigInteger u2 = r.multiply(w).mod(CryptoConstants.dsaq); BigInteger u2 = r.multiply(w).mod(CryptoConstants.dsaq);
BigInteger v = ((CryptoConstants.dsag.modPow(u1, CryptoConstants.dsap)) BigInteger modval = CryptoConstants.dsag.modPow(u1, CryptoConstants.dsap);
.multiply(y.modPow(u2, BigInteger modmulval = modval.multiply(y.modPow(u2,CryptoConstants.dsap));
CryptoConstants.dsap))) BigInteger v = (modmulval).mod(CryptoConstants.dsap).mod(CryptoConstants.dsaq);
.mod(
CryptoConstants.dsap)
.mod(
CryptoConstants.dsaq);
boolean ok = v.compareTo(r) == 0; boolean ok = v.compareTo(r) == 0;
long diff = Clock.getInstance().now() - start; long diff = _context.clock().now() - start;
if (diff > 1000) { 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; return ok;
@ -88,13 +91,13 @@ public class DSAEngine {
public Signature sign(byte data[], SigningPrivateKey signingKey) { public Signature sign(byte data[], SigningPrivateKey signingKey) {
if ((signingKey == null) || (data == null) || (data.length <= 0)) return null; if ((signingKey == null) || (data == null) || (data.length <= 0)) return null;
long start = Clock.getInstance().now(); long start = _context.clock().now();
Signature sig = new Signature(); Signature sig = new Signature();
BigInteger k; BigInteger k;
do { do {
k = new BigInteger(160, RandomSource.getInstance()); k = new BigInteger(160, _context.random());
} while (k.compareTo(CryptoConstants.dsaq) != 1); } while (k.compareTo(CryptoConstants.dsaq) != 1);
BigInteger r = CryptoConstants.dsag.modPow(k, CryptoConstants.dsap).mod(CryptoConstants.dsaq); BigInteger r = CryptoConstants.dsag.modPow(k, CryptoConstants.dsap).mod(CryptoConstants.dsaq);
@ -139,7 +142,7 @@ public class DSAEngine {
} }
sig.setData(out); sig.setData(out);
long diff = Clock.getInstance().now() - start; long diff = _context.clock().now() - start;
if (diff > 1000) { if (diff > 1000) {
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to sign (" + diff + "ms)"); if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to sign (" + diff + "ms)");
} }

View File

@ -17,6 +17,7 @@ import net.i2p.data.Hash;
import net.i2p.data.PrivateKey; import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey; import net.i2p.data.PublicKey;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Fake ElG E and D, useful for when performance isn't being tested * Fake ElG E and D, useful for when performance isn't being tested
@ -26,10 +27,18 @@ import net.i2p.util.Log;
public class DummyElGamalEngine extends ElGamalEngine { public class DummyElGamalEngine extends ElGamalEngine {
private final static Log _log = new Log(DummyElGamalEngine.class); 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!", _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")); new Exception("I really hope you know what you're doing"));
} }
private DummyElGamalEngine() { super(null); }
/** encrypt the data to the public key /** encrypt the data to the public key
* @return encrypted data * @return encrypted data

View File

@ -29,6 +29,7 @@ import net.i2p.stat.StatManager;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Handles the actual ElGamal+AES encryption and decryption scenarios using the * Handles the actual ElGamal+AES encryption and decryption scenarios using the
@ -37,26 +38,25 @@ import net.i2p.util.RandomSource;
public class ElGamalAESEngine { public class ElGamalAESEngine {
private final static Log _log = new Log(ElGamalAESEngine.class); private final static Log _log = new Log(ElGamalAESEngine.class);
private final static int MIN_ENCRYPTED_SIZE = 80; // smallest possible resulting size private final static int MIN_ENCRYPTED_SIZE = 80; // smallest possible resulting size
private I2PAppContext _context;
static { private ElGamalAESEngine() {}
StatManager.getInstance() public ElGamalAESEngine(I2PAppContext ctx) {
.createFrequencyStat("crypto.elGamalAES.encryptNewSession", _context = ctx;
_context.statManager().createFrequencyStat("crypto.elGamalAES.encryptNewSession",
"how frequently we encrypt to a new ElGamal/AES+SessionTag session?", "how frequently we encrypt to a new ElGamal/AES+SessionTag session?",
"Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); "Encryption", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l});
StatManager.getInstance() _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptExistingSession",
.createFrequencyStat("crypto.elGamalAES.encryptExistingSession",
"how frequently we encrypt to an existing ElGamal/AES+SessionTag session?", "how frequently we encrypt to an existing ElGamal/AES+SessionTag session?",
"Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
StatManager.getInstance() _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptNewSession",
.createFrequencyStat("crypto.elGamalAES.decryptNewSession",
"how frequently we decrypt with a new ElGamal/AES+SessionTag session?", "how frequently we decrypt with a new ElGamal/AES+SessionTag session?",
"Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
StatManager.getInstance() _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptExistingSession",
.createFrequencyStat("crypto.elGamalAES.decryptExistingSession",
"how frequently we decrypt with an existing ElGamal/AES+SessionTag session?", "how frequently we decrypt with an existing ElGamal/AES+SessionTag session?",
"Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
StatManager.getInstance() _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptFail",
.createFrequencyStat("crypto.elGamalAES.decryptFail",
"how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption", "how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption",
new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
} }
@ -66,7 +66,7 @@ public class ElGamalAESEngine {
* ElGamal+AES algorithm in the data structure spec. * 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 (data == null) {
if (_log.shouldLog(Log.WARN)) _log.warn("Null data being decrypted?"); if (_log.shouldLog(Log.WARN)) _log.warn("Null data being decrypted?");
return null; return null;
@ -79,7 +79,7 @@ public class ElGamalAESEngine {
byte tag[] = new byte[32]; byte tag[] = new byte[32];
System.arraycopy(data, 0, tag, 0, tag.length); System.arraycopy(data, 0, tag, 0, tag.length);
SessionTag st = new SessionTag(tag); SessionTag st = new SessionTag(tag);
SessionKey key = SessionKeyManager.getInstance().consumeTag(st); SessionKey key = _context.sessionKeyManager().consumeTag(st);
SessionKey foundKey = new SessionKey(); SessionKey foundKey = new SessionKey();
foundKey.setData(null); foundKey.setData(null);
SessionKey usedKey = new SessionKey(); SessionKey usedKey = new SessionKey();
@ -90,16 +90,16 @@ public class ElGamalAESEngine {
usedKey.setData(key.getData()); usedKey.setData(key.getData());
decrypted = decryptExistingSession(data, key, targetPrivateKey, foundTags, usedKey, foundKey); decrypted = decryptExistingSession(data, key, targetPrivateKey, foundTags, usedKey, foundKey);
if (decrypted != null) if (decrypted != null)
StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptExistingSession"); _context.statManager().updateFrequency("crypto.elGamalAES.decryptExistingSession");
else else
StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptFailed"); _context.statManager().updateFrequency("crypto.elGamalAES.decryptFailed");
} else { } else {
if (_log.shouldLog(Log.DEBUG)) _log.debug("Key is NOT known for tag " + st); if (_log.shouldLog(Log.DEBUG)) _log.debug("Key is NOT known for tag " + st);
decrypted = decryptNewSession(data, targetPrivateKey, foundTags, usedKey, foundKey); decrypted = decryptNewSession(data, targetPrivateKey, foundTags, usedKey, foundKey);
if (decrypted != null) if (decrypted != null)
StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptNewSession"); _context.statManager().updateFrequency("crypto.elGamalAES.decryptNewSession");
else else
StatManager.getInstance().updateFrequency("crypto.elGamalAES.decryptFailed"); _context.statManager().updateFrequency("crypto.elGamalAES.decryptFailed");
} }
if ((key == null) && (decrypted == null)) { if ((key == null) && (decrypted == null)) {
@ -109,10 +109,10 @@ public class ElGamalAESEngine {
if (foundTags.size() > 0) { if (foundTags.size() > 0) {
if (foundKey.getData() != null) { if (foundKey.getData() != null) {
if (_log.shouldLog(Log.DEBUG)) _log.debug("Found key: " + foundKey); if (_log.shouldLog(Log.DEBUG)) _log.debug("Found key: " + foundKey);
SessionKeyManager.getInstance().tagsReceived(foundKey, foundTags); _context.sessionKeyManager().tagsReceived(foundKey, foundTags);
} else { } else {
if (_log.shouldLog(Log.DEBUG)) _log.debug("Used key: " + usedKey); if (_log.shouldLog(Log.DEBUG)) _log.debug("Used key: " + usedKey);
SessionKeyManager.getInstance().tagsReceived(usedKey, foundTags); _context.sessionKeyManager().tagsReceived(usedKey, foundTags);
} }
} }
return decrypted; return decrypted;
@ -132,7 +132,7 @@ public class ElGamalAESEngine {
* *
* @return null if decryption fails * @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 { SessionKey foundKey) throws DataFormatException {
if (data == null) { if (data == null) {
if (_log.shouldLog(Log.WARN)) _log.warn("Data is null, unable to decrypt new session"); if (_log.shouldLog(Log.WARN)) _log.warn("Data is null, unable to decrypt new session");
@ -147,7 +147,7 @@ public class ElGamalAESEngine {
} else { } else {
System.arraycopy(data, 0, elgEncr, 514 - data.length, data.length); 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; if (elgDecr == null) return null;
ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr); ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr);
@ -170,7 +170,7 @@ public class ElGamalAESEngine {
//_log.debug("Pre IV for decryptNewSession: " + DataHelper.toString(preIV, 32)); //_log.debug("Pre IV for decryptNewSession: " + DataHelper.toString(preIV, 32));
//_log.debug("SessionKey for decryptNewSession: " + DataHelper.toString(key.getData(), 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]; byte iv[] = new byte[16];
System.arraycopy(ivHash.getData(), 0, iv, 0, 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 * @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 { SessionKey usedKey, SessionKey foundKey) throws DataFormatException {
byte preIV[] = new byte[32]; byte preIV[] = new byte[32];
System.arraycopy(data, 0, preIV, 0, preIV.length); System.arraycopy(data, 0, preIV, 0, preIV.length);
byte encr[] = new byte[data.length - 32]; byte encr[] = new byte[data.length - 32];
System.arraycopy(data, 32, encr, 0, encr.length); 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]; byte iv[] = new byte[16];
System.arraycopy(ivHash.getData(), 0, iv, 0, 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 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 * @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 { SessionKey foundKey) throws DataFormatException {
//_log.debug("iv for decryption: " + DataHelper.toString(iv, 16)); //_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)); //_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); byte decrypted[] = _context.AESEngine().decrypt(encrypted, key, iv);
Hash h = SHA256Generator.getInstance().calculateHash(decrypted); Hash h = _context.sha().calculateHash(decrypted);
//_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); //_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32));
try { try {
SessionKey newKey = null; SessionKey newKey = null;
@ -289,7 +289,7 @@ public class ElGamalAESEngine {
byte unencrData[] = new byte[(int) len]; byte unencrData[] = new byte[(int) len];
read = bais.read(unencrData); read = bais.read(unencrData);
if (read != unencrData.length) throw new Exception("Invalid size of the data read"); 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)) { if (calcHash.equals(readHash)) {
// everything matches. w00t. // everything matches. w00t.
foundTags.addAll(tags); 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 * @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) * 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) { SessionTag currentTag, SessionKey newKey, long paddedSize) {
if (currentTag == null) { if (currentTag == null) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Current tag is null, encrypting as new session", new Exception("encrypt new")); _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); return encryptNewSession(data, target, key, tagsForDelivery, newKey, paddedSize);
} else { } else {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Current tag is NOT null, encrypting as existing session", new Exception("encrypt existing")); _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); 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 * 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) { SessionTag currentTag, long paddedSize) {
return encrypt(data, target, key, tagsForDelivery, currentTag, null, 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 * 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); return encrypt(data, target, key, tagsForDelivery, null, null, paddedSize);
} }
/** /**
* Encrypt the data to the target using the given key delivering no tags * 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); 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 * - 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) { SessionKey newKey, long paddedSize) {
//_log.debug("Encrypting to a NEW session"); //_log.debug("Encrypting to a NEW session");
try { try {
ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(64); ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(64);
key.writeBytes(elgSrc); key.writeBytes(elgSrc);
byte preIV[] = new byte[32]; byte preIV[] = new byte[32];
RandomSource.getInstance().nextBytes(preIV); _context.random().nextBytes(preIV);
elgSrc.write(preIV); elgSrc.write(preIV);
byte rnd[] = new byte[158]; byte rnd[] = new byte[158];
RandomSource.getInstance().nextBytes(rnd); _context.random().nextBytes(rnd);
elgSrc.write(rnd); elgSrc.write(rnd);
elgSrc.flush(); elgSrc.flush();
//_log.debug("Pre IV for encryptNewSession: " + DataHelper.toString(preIV, 32)); //_log.debug("Pre IV for encryptNewSession: " + DataHelper.toString(preIV, 32));
//_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32)); //_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32));
long before = Clock.getInstance().now(); long before = _context.clock().now();
byte elgEncr[] = ElGamalEngine.getInstance().encrypt(elgSrc.toByteArray(), target); byte elgEncr[] = _context.elGamalEngine().encrypt(elgSrc.toByteArray(), target);
long after = Clock.getInstance().now(); long after = _context.clock().now();
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("elgEngine.encrypt of the session key took " + (after - before) + "ms"); _log.info("elgEngine.encrypt of the session key took " + (after - before) + "ms");
if (elgEncr.length < 514) { if (elgEncr.length < 514) {
@ -400,7 +400,7 @@ public class ElGamalAESEngine {
} }
//_log.debug("ElGamal encrypted length: " + elgEncr.length + " elGamal source length: " + elgSrc.toByteArray().length); //_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]; byte iv[] = new byte[16];
System.arraycopy(ivHash.getData(), 0, iv, 0, 16); System.arraycopy(ivHash.getData(), 0, iv, 0, 16);
byte aesEncr[] = encryptAESBlock(data, key, iv, tagsForDelivery, newKey, paddedSize); 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(elgEncr, 0, rv, 0, elgEncr.length);
System.arraycopy(aesEncr, 0, rv, elgEncr.length, aesEncr.length); System.arraycopy(aesEncr, 0, rv, elgEncr.length, aesEncr.length);
//_log.debug("Return length: " + rv.length); //_log.debug("Return length: " + rv.length);
long finish = Clock.getInstance().now(); long finish = _context.clock().now();
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("after the elgEngine.encrypt took a total of " + (finish - after) + "ms"); _log.debug("after the elgEngine.encrypt took a total of " + (finish - after) + "ms");
return rv; return rv;
@ -436,14 +436,14 @@ public class ElGamalAESEngine {
* - random bytes, padding the total size to greater than paddedSize with a mod 16 = 0 * - 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) { SessionTag currentTag, SessionKey newKey, long paddedSize) {
//_log.debug("Encrypting to an EXISTING session"); //_log.debug("Encrypting to an EXISTING session");
byte rawTag[] = currentTag.getData(); byte rawTag[] = currentTag.getData();
//_log.debug("Pre IV for encryptExistingSession (aka tag): " + currentTag.toString()); //_log.debug("Pre IV for encryptExistingSession (aka tag): " + currentTag.toString());
//_log.debug("SessionKey for encryptNewSession: " + DataHelper.toString(key.getData(), 32)); //_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]; byte iv[] = new byte[16];
System.arraycopy(ivHash.getData(), 0, iv, 0, 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 * - 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) { long paddedSize) {
//_log.debug("iv for encryption: " + DataHelper.toString(iv, 16)); //_log.debug("iv for encryption: " + DataHelper.toString(iv, 16));
//_log.debug("Encrypting AES"); //_log.debug("Encrypting AES");
@ -484,7 +484,7 @@ public class ElGamalAESEngine {
//_log.debug("# tags created, registered, and written: " + tags.size()); //_log.debug("# tags created, registered, and written: " + tags.size());
DataHelper.writeLong(aesSrc, 4, data.length); DataHelper.writeLong(aesSrc, 4, data.length);
//_log.debug("data length: " + data.length); //_log.debug("data length: " + data.length);
Hash hash = SHA256Generator.getInstance().calculateHash(data); Hash hash = _context.sha().calculateHash(data);
hash.writeBytes(aesSrc); hash.writeBytes(aesSrc);
//_log.debug("hash of data: " + DataHelper.toString(hash.getData(), 32)); //_log.debug("hash of data: " + DataHelper.toString(hash.getData(), 32));
if (newKey == null) { if (newKey == null) {
@ -499,14 +499,14 @@ public class ElGamalAESEngine {
aesSrc.write(data); aesSrc.write(data);
int len = aesSrc.toByteArray().length; int len = aesSrc.toByteArray().length;
//_log.debug("raw data written: " + len); //_log.debug("raw data written: " + len);
byte padding[] = getPadding(len, paddedSize); byte padding[] = getPadding(_context, len, paddedSize);
//_log.debug("padding length: " + padding.length); //_log.debug("padding length: " + padding.length);
aesSrc.write(padding); aesSrc.write(padding);
byte aesUnencr[] = aesSrc.toByteArray(); 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)); //_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); //_log.debug("Encrypted length: " + aesEncr.length);
return aesEncr; return aesEncr;
} catch (IOException ioe) { } catch (IOException ioe) {
@ -523,7 +523,7 @@ public class ElGamalAESEngine {
* at least minPaddedSize * at least minPaddedSize
* *
*/ */
final static byte[] getPadding(int curSize, long minPaddedSize) { final static byte[] getPadding(I2PAppContext context, int curSize, long minPaddedSize) {
int diff = 0; int diff = 0;
if (curSize < minPaddedSize) { if (curSize < minPaddedSize) {
diff = (int) minPaddedSize - curSize; diff = (int) minPaddedSize - curSize;
@ -532,7 +532,7 @@ public class ElGamalAESEngine {
int numPadding = diff; int numPadding = diff;
if (((curSize + diff) % 16) != 0) numPadding += (16 - ((curSize + diff) % 16)); if (((curSize + diff) % 16) != 0) numPadding += (16 - ((curSize + diff) % 16));
byte rv[] = new byte[numPadding]; byte rv[] = new byte[numPadding];
RandomSource.getInstance().nextBytes(rv); context.random().nextBytes(rv);
return rv; return rv;
} }

View File

@ -43,6 +43,7 @@ import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Wrapper for ElGamal encryption/signature schemes. * Wrapper for ElGamal encryption/signature schemes.
@ -56,25 +57,28 @@ import net.i2p.util.RandomSource;
*/ */
public class ElGamalEngine { public class ElGamalEngine {
private final static Log _log = new Log(ElGamalEngine.class); private Log _log;
private static ElGamalEngine _engine; private I2PAppContext _context;
static {
if ("off".equals(System.getProperty("i2p.encryption", "on")))
_engine = new DummyElGamalEngine();
else
_engine = new ElGamalEngine();
StatManager.getInstance().createRateStat("crypto.elGamal.encrypt", /**
* 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", "how long does it take to do a full ElGamal encryption", "Encryption",
new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000});
StatManager.getInstance().createRateStat("crypto.elGamal.decrypt", context.statManager().createRateStat("crypto.elGamal.decrypt",
"how long does it take to do a full ElGamal decryption", "Encryption", "how long does it take to do a full ElGamal decryption", "Encryption",
new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); 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 final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02});
private BigInteger[] getNextYK() { private BigInteger[] getNextYK() {
@ -91,12 +95,12 @@ public class ElGamalEngine {
throw new IllegalArgumentException("Data to encrypt must be < 223 bytes at the moment"); throw new IllegalArgumentException("Data to encrypt must be < 223 bytes at the moment");
if (publicKey == null) throw new IllegalArgumentException("Null public key specified"); 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); ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
try { try {
baos.write(0xFF); baos.write(0xFF);
Hash hash = SHA256Generator.getInstance().calculateHash(data); Hash hash = _context.sha().calculateHash(data);
hash.writeBytes(baos); hash.writeBytes(baos);
baos.write(data); baos.write(data);
baos.flush(); baos.flush();
@ -106,25 +110,25 @@ public class ElGamalEngine {
} }
byte d2[] = baos.toByteArray(); byte d2[] = baos.toByteArray();
long t0 = Clock.getInstance().now(); long t0 = _context.clock().now();
BigInteger m = new NativeBigInteger(1, d2); BigInteger m = new NativeBigInteger(1, d2);
long t1 = Clock.getInstance().now(); long t1 = _context.clock().now();
if (m.compareTo(CryptoConstants.elgp) >= 0) if (m.compareTo(CryptoConstants.elgp) >= 0)
throw new IllegalArgumentException("ARGH. Data cannot be larger than the ElGamal prime. FIXME"); 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()); BigInteger aalpha = new NativeBigInteger(1, publicKey.getData());
long t3 = Clock.getInstance().now(); long t3 = _context.clock().now();
BigInteger yk[] = getNextYK(); BigInteger yk[] = getNextYK();
BigInteger k = yk[1]; BigInteger k = yk[1];
BigInteger y = yk[0]; BigInteger y = yk[0];
long t7 = Clock.getInstance().now(); long t7 = _context.clock().now();
BigInteger d = aalpha.modPow(k, CryptoConstants.elgp); BigInteger d = aalpha.modPow(k, CryptoConstants.elgp);
long t8 = Clock.getInstance().now(); long t8 = _context.clock().now();
d = d.multiply(m); d = d.multiply(m);
long t9 = Clock.getInstance().now(); long t9 = _context.clock().now();
d = d.mod(CryptoConstants.elgp); d = d.mod(CryptoConstants.elgp);
long t10 = Clock.getInstance().now(); long t10 = _context.clock().now();
byte[] ybytes = y.toByteArray(); byte[] ybytes = y.toByteArray();
byte[] dbytes = d.toByteArray(); byte[] dbytes = d.toByteArray();
@ -146,14 +150,14 @@ public class ElGamalEngine {
buf.append("8-9: ").append(t9 - t8).append('\n'); buf.append("8-9: ").append(t9 - t8).append('\n');
buf.append("9-10: ").append(t10 - t9).append('\n'); buf.append("9-10: ").append(t10 - t9).append('\n');
//_log.debug(buf.toString()); //_log.debug(buf.toString());
long end = Clock.getInstance().now(); long end = _context.clock().now();
long diff = end - start; long diff = end - start;
if (diff > 1000) { if (diff > 1000) {
if (_log.shouldLog(Log.WARN)) _log.warn("Took too long to encrypt ElGamal block (" + diff + "ms)"); 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; return out;
} }
@ -165,7 +169,7 @@ public class ElGamalEngine {
public byte[] decrypt(byte encrypted[], PrivateKey privateKey) { public byte[] decrypt(byte encrypted[], PrivateKey privateKey) {
if ((encrypted == null) || (encrypted.length > 514)) if ((encrypted == null) || (encrypted.length > 514))
throw new IllegalArgumentException("Data to decrypt must be <= 514 bytes at the moment"); 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[] ybytes = new byte[257];
byte[] dbytes = new byte[257]; byte[] dbytes = new byte[257];
@ -196,10 +200,10 @@ public class ElGamalEngine {
return null; return null;
} }
Hash calcHash = SHA256Generator.getInstance().calculateHash(rv); Hash calcHash = _context.sha().calculateHash(rv);
boolean ok = calcHash.equals(hash); boolean ok = calcHash.equals(hash);
long end = Clock.getInstance().now(); long end = _context.clock().now();
long diff = end - start; long diff = end - start;
if (diff > 1000) { if (diff > 1000) {
@ -207,7 +211,7 @@ public class ElGamalEngine {
_log.warn("Took too long to decrypt and verify ElGamal block (" + diff + "ms)"); _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) { if (ok) {
//_log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length)); //_log.debug("Hash matches: " + DataHelper.toString(hash.getData(), hash.getData().length));
@ -236,6 +240,7 @@ public class ElGamalEngine {
} }
RandomSource.getInstance().nextBoolean(); RandomSource.getInstance().nextBoolean();
I2PAppContext context = new I2PAppContext();
System.out.println("Running " + numRuns + " times"); System.out.println("Running " + numRuns + " times");
@ -249,9 +254,9 @@ public class ElGamalEngine {
byte buf[] = new byte[128]; byte buf[] = new byte[128];
RandomSource.getInstance().nextBytes(buf); RandomSource.getInstance().nextBytes(buf);
long startE = Clock.getInstance().now(); long startE = Clock.getInstance().now();
byte encr[] = ElGamalEngine.getInstance().encrypt(buf, pubkey); byte encr[] = context.elGamalEngine().encrypt(buf, pubkey);
long endE = Clock.getInstance().now(); long endE = Clock.getInstance().now();
byte decr[] = ElGamalEngine.getInstance().decrypt(encr, privkey); byte decr[] = context.elGamalEngine().decrypt(encr, privkey);
long endD = Clock.getInstance().now(); long endD = Clock.getInstance().now();
eTime += endE - startE; eTime += endE - startE;
dTime += endD - endE; dTime += endD - endE;
@ -259,8 +264,7 @@ public class ElGamalEngine {
if (!DataHelper.eq(decr, buf)) { if (!DataHelper.eq(decr, buf)) {
System.out.println("PublicKey : " + DataHelper.toString(pubkey.getData(), pubkey.getData().length)); System.out.println("PublicKey : " + DataHelper.toString(pubkey.getData(), pubkey.getData().length));
System.out.println("PrivateKey : " System.out.println("PrivateKey : " + DataHelper.toString(privkey.getData(), privkey.getData().length));
+ DataHelper.toString(privkey.getData(), privkey.getData().length));
System.out.println("orig : " + DataHelper.toString(buf, buf.length)); System.out.println("orig : " + DataHelper.toString(buf, buf.length));
System.out.println("d(e(orig) : " + DataHelper.toString(decr, decr.length)); System.out.println("d(e(orig) : " + DataHelper.toString(decr, decr.length));
System.out.println("orig.len : " + buf.length); System.out.println("orig.len : " + buf.length);

View File

@ -3,28 +3,23 @@ package net.i2p.crypto;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.I2PAppContext;
/** /**
* Calculate the HMAC-SHA256 of a key+message. Currently FAKE - returns a stupid * Calculate the HMAC-SHA256 of a key+message. Currently FAKE - returns a stupid
* kludgy hash: H(H(key) XOR H(data)). Fix me! * kludgy hash: H(H(key) XOR H(data)). Fix me!
* *
*/ */
public abstract class HMACSHA256Generator { public class HMACSHA256Generator {
private static HMACSHA256Generator _generator = new DummyHMACSHA256Generator(); public HMACSHA256Generator(I2PAppContext context) {};
public static HMACSHA256Generator getInstance() { public static HMACSHA256Generator getInstance() {
return _generator; return I2PAppContext.getGlobalContext().hmac();
} }
public abstract Hash calculate(SessionKey key, byte data[]); /**
} * This should calculate the HMAC/SHA256, but it DOESNT. Its just a kludge.
* Fix me.
/**
* jrandom smells.
*
*/ */
class DummyHMACSHA256Generator extends HMACSHA256Generator {
public Hash calculate(SessionKey key, byte data[]) { public Hash calculate(SessionKey key, byte data[]) {
if ((key == null) || (key.getData() == null) || (data == null)) if ((key == null) || (key.getData() == null) || (data == null))
throw new NullPointerException("Null arguments for HMAC"); throw new NullPointerException("Null arguments for HMAC");

View File

@ -22,18 +22,24 @@ import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** Define a way of generating asymetrical key pairs as well as symetrical keys /** Define a way of generating asymetrical key pairs as well as symetrical keys
* @author jrandom * @author jrandom
*/ */
public class KeyGenerator { public class KeyGenerator {
private final static Log _log = new Log(KeyGenerator.class); private Log _log;
private static final RandomSource _random = RandomSource.getInstance(); private I2PAppContext _context;
private static KeyGenerator _generator = new KeyGenerator();
public static KeyGenerator getInstance() { public KeyGenerator(I2PAppContext context) {
return _generator; _log = context.logManager().getLog(KeyGenerator.class);
_context = context;
} }
public static KeyGenerator getInstance() {
return I2PAppContext.getGlobalContext().keyGenerator();
}
/** Generate a private 256 bit session key /** Generate a private 256 bit session key
* @return session key * @return session key
@ -42,7 +48,7 @@ public class KeyGenerator {
// 256bit random # as a session key // 256bit random # as a session key
SessionKey key = new SessionKey(); SessionKey key = new SessionKey();
byte data[] = new byte[SessionKey.KEYSIZE_BYTES]; byte data[] = new byte[SessionKey.KEYSIZE_BYTES];
_random.nextBytes(data); _context.random().nextBytes(data);
key.setData(data); key.setData(data);
return key; return key;
} }
@ -52,7 +58,7 @@ public class KeyGenerator {
* @return pair of keys * @return pair of keys
*/ */
public Object[] generatePKIKeypair() { public Object[] generatePKIKeypair() {
BigInteger a = new NativeBigInteger(2048, _random); BigInteger a = new NativeBigInteger(2048, _context.random());
BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp); BigInteger aalpha = CryptoConstants.elgg.modPow(a, CryptoConstants.elgp);
Object[] keys = new Object[2]; Object[] keys = new Object[2];
@ -80,7 +86,7 @@ public class KeyGenerator {
// make sure the random key is less than the DSA q // make sure the random key is less than the DSA q
do { do {
x = new NativeBigInteger(160, _random); x = new NativeBigInteger(160, _context.random());
} while (x.compareTo(CryptoConstants.dsaq) >= 0); } while (x.compareTo(CryptoConstants.dsaq) >= 0);
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap); BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
@ -118,13 +124,14 @@ public class KeyGenerator {
byte src[] = new byte[200]; byte src[] = new byte[200];
RandomSource.getInstance().nextBytes(src); RandomSource.getInstance().nextBytes(src);
I2PAppContext ctx = new I2PAppContext();
long time = 0; long time = 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
long start = Clock.getInstance().now(); long start = Clock.getInstance().now();
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
long end = Clock.getInstance().now(); long end = Clock.getInstance().now();
byte ctext[] = ElGamalEngine.getInstance().encrypt(src, (PublicKey) keys[0]); byte ctext[] = ctx.elGamalEngine().encrypt(src, (PublicKey) keys[0]);
byte ptext[] = ElGamalEngine.getInstance().decrypt(ctext, (PrivateKey) keys[1]); byte ptext[] = ctx.elGamalEngine().decrypt(ctext, (PrivateKey) keys[1]);
time += end - start; time += end - start;
if (DataHelper.eq(ptext, src)) if (DataHelper.eq(ptext, src))
log.debug("D(E(data)) == data"); log.debug("D(E(data)) == data");

View File

@ -27,6 +27,7 @@ import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag; import net.i2p.data.SessionTag;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Expose the functionality to allow people to write out and read in the * 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; 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 * Write the session key data to the given stream
* *
@ -146,7 +160,8 @@ public class PersistentSessionKeyManager extends TransientSessionKeyManager {
} }
public static void main(String args[]) { public static void main(String args[]) {
PersistentSessionKeyManager mgr = new PersistentSessionKeyManager(); I2PAppContext ctx = new I2PAppContext();
PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)ctx.sessionKeyManager();
try { try {
mgr.loadState(new FileInputStream("sessionKeys.dat")); mgr.loadState(new FileInputStream("sessionKeys.dat"));
String state = mgr.renderStatusHTML(); String state = mgr.renderStatusHTML();

View File

@ -30,6 +30,7 @@ package net.i2p.crypto;
*/ */
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.I2PAppContext;
/** Defines a wrapper for SHA-256 operation /** Defines a wrapper for SHA-256 operation
* *
@ -38,10 +39,9 @@ import net.i2p.data.Hash;
* @author thecrypto,jrandom * @author thecrypto,jrandom
*/ */
public class SHA256Generator { public class SHA256Generator {
private static SHA256Generator _generator = new SHA256Generator(); public SHA256Generator(I2PAppContext context) {};
public static SHA256Generator getInstance() { public static SHA256Generator getInstance() {
return _generator; return I2PAppContext.getGlobalContext().sha();
} }
static int[] K = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, static int[] K = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,

View File

@ -14,6 +14,7 @@ import java.util.Set;
import net.i2p.data.PublicKey; import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag; import net.i2p.data.SessionTag;
import net.i2p.I2PAppContext;
/** /**
* Manage the session keys and session tags used for encryption and decryption. * Manage the session keys and session tags used for encryption and decryption.
@ -23,11 +24,10 @@ import net.i2p.data.SessionTag;
* *
*/ */
public class SessionKeyManager { public class SessionKeyManager {
private final static SessionKeyManager _instance = new PersistentSessionKeyManager(); // new TransientSessionKeyManager(); // SessionKeyManager(); /** session key managers must be created through an app context */
protected SessionKeyManager(I2PAppContext context) {}
public final static SessionKeyManager getInstance() { /** see above */
return _instance; private SessionKeyManager() {}
}
/** /**
* Retrieve the session key currently associated with encryption to the target, * Retrieve the session key currently associated with encryption to the target,

View File

@ -18,6 +18,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.PublicKey; import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey; 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 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 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); _outboundSessions = new HashMap(64);
_inboundTagSets = new HashMap(1024); _inboundTagSets = new HashMap(1024);
} }
private TransientSessionKeyManager() { super(null); }
/** TagSet */ /** TagSet */
protected Set getInboundTagSets() { protected Set getInboundTagSets() {

View File

@ -18,6 +18,7 @@ import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.NativeBigInteger; import net.i2p.util.NativeBigInteger;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Precalculate the Y and K for ElGamal encryption operations. * Precalculate the Y and K for ElGamal encryption operations.
@ -56,22 +57,23 @@ class YKGenerator {
private final static long CHECK_DELAY = 30 * 1000; private final static long CHECK_DELAY = 30 * 1000;
static { static {
I2PAppContext ctx = I2PAppContext.getGlobalContext();
try { 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; MIN_NUM_BUILDERS = val;
} catch (Throwable t) { } catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_YK_PRECALC_MIN); int val = Integer.parseInt(DEFAULT_YK_PRECALC_MIN);
MIN_NUM_BUILDERS = val; MIN_NUM_BUILDERS = val;
} }
try { 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; MAX_NUM_BUILDERS = val;
} catch (Throwable t) { } catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_YK_PRECALC_MAX); int val = Integer.parseInt(DEFAULT_YK_PRECALC_MAX);
MAX_NUM_BUILDERS = val; MAX_NUM_BUILDERS = val;
} }
try { 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; CALC_DELAY = val;
} catch (Throwable t) { } catch (Throwable t) {
int val = Integer.parseInt(DEFAULT_YK_PRECALC_DELAY); int val = Integer.parseInt(DEFAULT_YK_PRECALC_DELAY);

View File

@ -35,7 +35,6 @@ import net.i2p.util.OrderedProperties;
* @author jrandom * @author jrandom
*/ */
public class DataHelper { public class DataHelper {
private final static Log _log = new Log(DataHelper.class);
private final static String _equal = "="; // in UTF-8 private final static String _equal = "="; // in UTF-8
private final static String _semicolon = ";"; // 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 * @throws IOException if there is a problem reading the data
* @return mapping * @return mapping
*/ */
public static Properties readProperties(InputStream rawStream) throws DataFormatException, IOException { public static Properties readProperties(InputStream rawStream)
throws DataFormatException, IOException {
Properties props = new OrderedProperties(); Properties props = new OrderedProperties();
long size = readLong(rawStream, 2); long size = readLong(rawStream, 2);
byte data[] = new byte[(int) size]; byte data[] = new byte[(int) size];
@ -65,25 +65,19 @@ public class DataHelper {
ByteArrayInputStream in = new ByteArrayInputStream(data); ByteArrayInputStream in = new ByteArrayInputStream(data);
byte eqBuf[] = _equal.getBytes(); byte eqBuf[] = _equal.getBytes();
byte semiBuf[] = _semicolon.getBytes(); byte semiBuf[] = _semicolon.getBytes();
try {
while (in.available() > 0) { while (in.available() > 0) {
String key = readString(in); String key = readString(in);
read = read(in, eqBuf); read = read(in, eqBuf);
if ((read != eqBuf.length) || (!eq(new String(eqBuf), _equal))) { if ((read != eqBuf.length) || (!eq(new String(eqBuf), _equal))) {
_log.debug("Failed eqtest [" + new String(eqBuf) + "]");
break; break;
} }
String val = readString(in); String val = readString(in);
read = read(in, semiBuf); read = read(in, semiBuf);
if ((read != semiBuf.length) || (!eq(new String(semiBuf), _semicolon))) { if ((read != semiBuf.length) || (!eq(new String(semiBuf), _semicolon))) {
_log.debug("Failed semitest [" + new String(semiBuf) + "]");
break; break;
} }
props.put(key, val); props.put(key, val);
} }
} catch (IOException ioe) {
_log.warn("Error reading properties", ioe);
}
return props; return props;
} }
@ -96,8 +90,8 @@ public class DataHelper {
* @throws DataFormatException if there is not enough valid data to write out * @throws DataFormatException if there is not enough valid data to write out
* @throws IOException if there is an IO error writing out the data * @throws IOException if there is an IO error writing out the data
*/ */
public static void writeProperties(OutputStream rawStream, Properties props) throws DataFormatException, public static void writeProperties(OutputStream rawStream, Properties props)
IOException { throws DataFormatException, IOException {
OrderedProperties p = new OrderedProperties(); OrderedProperties p = new OrderedProperties();
if (props != null) p.putAll(props); if (props != null) p.putAll(props);
ByteArrayOutputStream baos = new ByteArrayOutputStream(32); ByteArrayOutputStream baos = new ByteArrayOutputStream(32);
@ -204,10 +198,10 @@ public class DataHelper {
* @throws IOException if there is an IO error reading the number * @throws IOException if there is an IO error reading the number
* @return 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) if (numBytes > 8)
throw new DataFormatException( throw new DataFormatException("readLong doesn't currently support reading numbers > 8 bytes [as thats bigger than java's long]");
"readLong doesn't currently support reading numbers > 8 bytes [as thats bigger than java's long]");
byte data[] = new byte[numBytes]; byte data[] = new byte[numBytes];
int num = read(rawStream, data); int num = read(rawStream, data);
if (num != numBytes) 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 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 * @throws IOException if there is an IO error writing to the stream
*/ */
public static void writeLong(OutputStream rawStream, int numBytes, long value) throws DataFormatException, public static void writeLong(OutputStream rawStream, int numBytes, long value)
IOException { throws DataFormatException, IOException {
UnsignedInteger i = new UnsignedInteger(value); UnsignedInteger i = new UnsignedInteger(value);
rawStream.write(i.getBytes(numBytes)); rawStream.write(i.getBytes(numBytes));
} }
@ -254,7 +248,8 @@ public class DataHelper {
* @throws DataFormatException if the date is not valid * @throws DataFormatException if the date is not valid
* @throws IOException if there is an IO error writing the date * @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) if (date == null)
writeLong(out, 8, 0L); writeLong(out, 8, 0L);
else else
@ -286,7 +281,8 @@ public class DataHelper {
* @throws DataFormatException if the string is not valid * @throws DataFormatException if the string is not valid
* @throws IOException if there is an IO error writing the string * @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) { if (string == null) {
writeLong(out, 1, 0); writeLong(out, 1, 0);
} else { } else {
@ -328,7 +324,8 @@ public class DataHelper {
* @throws DataFormatException if the boolean is not valid * @throws DataFormatException if the boolean is not valid
* @throws IOException if there is an IO error writing the boolean * @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) if (bool == null)
writeLong(out, 1, 2); writeLong(out, 1, 2);
else if (Boolean.TRUE.equals(bool)) else if (Boolean.TRUE.equals(bool))
@ -353,7 +350,6 @@ public class DataHelper {
boolean eq = (((lhs == null) && (rhs == null)) || ((lhs != null) && (lhs.equals(rhs)))); boolean eq = (((lhs == null) && (rhs == null)) || ((lhs != null) && (lhs.equals(rhs))));
return eq; return eq;
} catch (ClassCastException cce) { } catch (ClassCastException cce) {
_log.warn("Error comparing [" + lhs + "] with [" + rhs + "]", cce);
return false; return false;
} }
} }
@ -542,12 +538,12 @@ public class DataHelper {
out.finish(); out.finish();
out.flush(); out.flush();
byte rv[] = baos.toByteArray(); byte rv[] = baos.toByteArray();
if (_log.shouldLog(Log.DEBUG)) //if (_log.shouldLog(Log.DEBUG))
_log.debug("Compression of " + orig.length + " into " + rv.length + " (or " + 100.0d // _log.debug("Compression of " + orig.length + " into " + rv.length + " (or " + 100.0d
* (((double) orig.length) / ((double) rv.length)) + "% savings)"); // * (((double) orig.length) / ((double) rv.length)) + "% savings)");
return rv; return rv;
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error compressing?!", ioe); //_log.error("Error compressing?!", ioe);
return null; return null;
} }
} }
@ -565,12 +561,12 @@ public class DataHelper {
baos.write(buf, 0, read); baos.write(buf, 0, read);
} }
byte rv[] = baos.toByteArray(); byte rv[] = baos.toByteArray();
if (_log.shouldLog(Log.DEBUG)) //if (_log.shouldLog(Log.DEBUG))
_log.debug("Decompression of " + orig.length + " into " + rv.length + " (or " + 100.0d // _log.debug("Decompression of " + orig.length + " into " + rv.length + " (or " + 100.0d
* (((double) rv.length) / ((double) orig.length)) + "% savings)"); // * (((double) rv.length) / ((double) orig.length)) + "% savings)");
return rv; return rv;
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error decompressing?", ioe); //_log.error("Error decompressing?", ioe);
return null; return null;
} }
} }

View File

@ -19,6 +19,7 @@ import net.i2p.crypto.SHA256Generator;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Component to manage the munging of hashes into routing keys - given a hash, * 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 { public class RoutingKeyGenerator {
private final static RoutingKeyGenerator _instance = new RoutingKeyGenerator(); private Log _log;
private I2PAppContext _context;
public static RoutingKeyGenerator getInstance() { public RoutingKeyGenerator(I2PAppContext context) {
return _instance; _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 byte _currentModData[];
private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT")); private final static Calendar _cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT"));
@ -67,7 +73,7 @@ public class RoutingKeyGenerator {
public void generateDateBasedModData() { public void generateDateBasedModData() {
Date today = null; Date today = null;
synchronized (_cal) { 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.HOUR_OF_DAY, 0);
_cal.set(Calendar.MINUTE, 0); _cal.set(Calendar.MINUTE, 0);
_cal.set(Calendar.SECOND, 0); _cal.set(Calendar.SECOND, 0);

View File

@ -6,24 +6,25 @@ import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
public class SimpleStatDumper { public class SimpleStatDumper {
private final static Log _log = new Log(SimpleStatDumper.class); 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; if (!_log.shouldLog(logLevel)) return;
StringBuffer buf = new StringBuffer(4 * 1024); StringBuffer buf = new StringBuffer(4 * 1024);
dumpFrequencies(buf); dumpFrequencies(context, buf);
dumpRates(buf); dumpRates(context, buf);
_log.log(logLevel, buf.toString()); _log.log(logLevel, buf.toString());
} }
private static void dumpFrequencies(StringBuffer buf) { private static void dumpFrequencies(I2PAppContext ctx, StringBuffer buf) {
Set frequencies = new TreeSet(StatManager.getInstance().getFrequencyNames()); Set frequencies = new TreeSet(ctx.statManager().getFrequencyNames());
for (Iterator iter = frequencies.iterator(); iter.hasNext();) { for (Iterator iter = frequencies.iterator(); iter.hasNext();) {
String name = (String) iter.next(); String name = (String) iter.next();
FrequencyStat freq = StatManager.getInstance().getFrequency(name); FrequencyStat freq = ctx.statManager().getFrequency(name);
buf.append('\n'); buf.append('\n');
buf.append(freq.getGroupName()).append('.').append(freq.getName()).append(": ") buf.append(freq.getGroupName()).append('.').append(freq.getName()).append(": ")
.append(freq.getDescription()).append('\n'); .append(freq.getDescription()).append('\n');
@ -39,11 +40,11 @@ public class SimpleStatDumper {
} }
} }
private static void dumpRates(StringBuffer buf) { private static void dumpRates(I2PAppContext ctx, StringBuffer buf) {
Set rates = new TreeSet(StatManager.getInstance().getRateNames()); Set rates = new TreeSet(ctx.statManager().getRateNames());
for (Iterator iter = rates.iterator(); iter.hasNext();) { for (Iterator iter = rates.iterator(); iter.hasNext();) {
String name = (String) iter.next(); String name = (String) iter.next();
RateStat rate = StatManager.getInstance().getRate(name); RateStat rate = ctx.statManager().getRate(name);
buf.append('\n'); buf.append('\n');
buf.append(rate.getGroupName()).append('.').append(rate.getName()).append(": ") buf.append(rate.getGroupName()).append('.').append(rate.getName()).append(": ")
.append(rate.getDescription()).append('\n'); .append(rate.getDescription()).append('\n');

View File

@ -10,6 +10,7 @@ import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Coordinate the management of various frequencies and rates within I2P components, * Coordinate the management of various frequencies and rates within I2P components,
@ -19,18 +20,23 @@ import net.i2p.util.Log;
* *
*/ */
public class StatManager { public class StatManager {
private final static Log _log = new Log(StatManager.class); private Log _log;
private final static StatManager _instance = new StatManager(); private I2PAppContext _context;
public final static StatManager getInstance() {
return _instance;
}
/** stat name to FrequencyStat */ /** stat name to FrequencyStat */
private Map _frequencyStats; private Map _frequencyStats;
/** stat name to RateStat */ /** stat name to RateStat */
private Map _rateStats; 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)); _frequencyStats = Collections.synchronizedMap(new HashMap(128));
_rateStats = 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) * @param periods array of period lengths (in milliseconds)
*/ */
public void createFrequencyStat(String name, String description, String group, long periods[]) { 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)); _frequencyStats.put(name, new FrequencyStat(name, description, group, periods));
} }
@ -56,6 +63,7 @@ public class StatManager {
* @param periods array of period lengths (in milliseconds) * @param periods array of period lengths (in milliseconds)
*/ */
public void createRateStat(String name, String description, String group, long periods[]) { 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)); _rateStats.put(name, new RateStat(name, description, group, periods));
} }

View File

@ -4,6 +4,8 @@ import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import net.i2p.I2PAppContext;
/** /**
* Alternate location for determining the time which takes into account an offset. * 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 * 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 { public class Clock {
private final static Log _log = new Log(Clock.class); private I2PAppContext _context;
private final static Clock _instance = new Clock(); public Clock(I2PAppContext context) {
_context = context;
public final static Clock getInstance() { _offset = 0;
return _instance; _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 volatile long _offset;
private boolean _alreadyChanged; private boolean _alreadyChanged;
private Set _listeners; 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) */ /** 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; 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 * 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. * 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) { public void setOffset(long offsetMs) {
if ((offsetMs > MAX_OFFSET) || (offsetMs < 0 - MAX_OFFSET)) { 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; return;
} }
long delta = offsetMs - _offset; long delta = offsetMs - _offset;
if ((delta < MIN_OFFSET_CHANGE) && (delta > 0 - MIN_OFFSET_CHANGE)) { 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; return;
} }
if (_alreadyChanged) 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 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; _alreadyChanged = true;
_offset = offsetMs; _offset = offsetMs;
fireOffsetChanged(delta); fireOffsetChanged(delta);

View File

@ -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 * 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: * 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 Class _class;
private String _name; private String _name;
private int _minPriority; private int _minPriority;
private LogScope _scope;
private LogManager _manager;
public final static int DEBUG = 10; public final static int DEBUG = 10;
public final static int INFO = 20; public final static int INFO = 20;
@ -65,32 +70,45 @@ public class Log {
} }
public Log(Class cls) { public Log(Class cls) {
this(cls, null); this(I2PAppContext.getGlobalContext().logManager(), cls, null);
_manager.addLog(this);
} }
public Log(String name) { 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; _class = cls;
_name = name; _name = name;
_minPriority = DEBUG; _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) { public void log(int priority, String msg) {
if (priority >= _minPriority) { if (priority >= _minPriority) {
LogManager.getInstance().addRecord( _manager.addRecord(new LogRecord(_class, _name,
new LogRecord(_class, _name, Thread.currentThread().getName(), priority, Thread.currentThread().getName(), priority,
msg, null)); msg, null));
} }
} }
public void log(int priority, String msg, Throwable t) { public void log(int priority, String msg, Throwable t) {
if (priority >= _minPriority) { if (priority >= _minPriority) {
LogManager.getInstance().addRecord( _manager.addRecord(new LogRecord(_class, _name,
new LogRecord(_class, _name, Thread.currentThread().getName(), priority, Thread.currentThread().getName(), priority,
msg, t)); msg, t));
} }
} }
@ -133,6 +151,9 @@ public class Log {
public void setMinimumPriority(int priority) { public void setMinimumPriority(int priority) {
_minPriority = 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) { public boolean shouldLog(int priority) {
@ -146,4 +167,31 @@ public class Log {
return _name; 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;
}
}
}
} }

View File

@ -1,26 +1,24 @@
package net.i2p.util; package net.i2p.util;
import java.util.LinkedList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.i2p.I2PAppContext;
/** /**
* Offer a glimpse into the last few console messages generated * Offer a glimpse into the last few console messages generated
* *
*/ */
public class LogConsoleBuffer { public class LogConsoleBuffer {
private final static LogConsoleBuffer _instance = new LogConsoleBuffer(); private I2PAppContext _context;
public final static LogConsoleBuffer getInstance() {
return _instance;
}
private List _buffer; private List _buffer;
private LogConsoleBuffer() { public LogConsoleBuffer(I2PAppContext context) {
_buffer = new LinkedList(); _context = context;
_buffer = new ArrayList();
} }
void add(String msg) { void add(String msg) {
int lim = LogManager.getInstance().getConsoleBufferSize(); int lim = _context.logManager().getConsoleBufferSize();
synchronized (_buffer) { synchronized (_buffer) {
while (_buffer.size() >= lim) while (_buffer.size() >= lim)
_buffer.remove(0); _buffer.remove(0);
@ -36,7 +34,7 @@ public class LogConsoleBuffer {
*/ */
public List getMostRecentMessages() { public List getMostRecentMessages() {
synchronized (_buffer) { synchronized (_buffer) {
return new LinkedList(_buffer); return new ArrayList(_buffer);
} }
} }
} }

View File

@ -19,6 +19,10 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.Set; 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, * 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 CONFIG_LOCATION_PROP = "loggerConfigLocation";
public final static String FILENAME_OVERRIDE_PROP = "loggerFilenameOverride"; public final static String FILENAME_OVERRIDE_PROP = "loggerFilenameOverride";
public final static String CONFIG_LOCATION_DEFAULT = "logger.config"; 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 * 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_DEFALTLEVEL = Log.STR_DEBUG;
public final static String DEFAULT_ONSCREENLEVEL = Log.STR_DEBUG; public final static String DEFAULT_ONSCREENLEVEL = Log.STR_DEBUG;
private I2PAppContext _context;
private Log _log;
private long _configLastRead; private long _configLastRead;
private String _location; private String _location;
private List _records; private List _records;
private Set _limits; private Set _limits;
private Set _logs; private Map _logs;
private LogWriter _writer; private LogWriter _writer;
private int _defaultLimit; private int _defaultLimit;
@ -84,6 +83,58 @@ public class LogManager {
private boolean _displayOnScreen; private boolean _displayOnScreen;
private int _consoleBufferSize; 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) { public void setDisplayOnScreen(boolean yes) {
_displayOnScreen = yes; _displayOnScreen = yes;
} }
@ -124,17 +175,6 @@ public class LogManager {
} }
} }
/**
* Called during Log construction
*
*/
void registerLog(Log log) {
synchronized (_logs) {
_logs.add(log);
}
updateLimit(log);
}
/** /**
* Called periodically by the log writer's thread * 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())) { if ((_configLastRead > 0) && (_configLastRead > cfgFile.lastModified())) {
_log.debug("Short circuiting config read"); _log.debug("Short circuiting config read");
return; return;
} else {
_log.debug("Loading config from " + _location);
} }
FileInputStream fis = null; FileInputStream fis = null;
try { try {
@ -212,7 +237,7 @@ public class LogManager {
_displayOnScreen = false; _displayOnScreen = false;
} }
String filenameOverride = System.getProperty(FILENAME_OVERRIDE_PROP); String filenameOverride = _context.getProperty(FILENAME_OVERRIDE_PROP);
if (filenameOverride != null) if (filenameOverride != null)
_baseLogfilename = filenameOverride; _baseLogfilename = filenameOverride;
else else
@ -297,11 +322,11 @@ public class LogManager {
} }
private void updateLimits() { private void updateLimits() {
Set logs = new HashSet(); Map logs = null;
synchronized (_logs) { 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(); Log log = (Log) iter.next();
updateLimit(log); updateLimit(log);
} }
@ -322,11 +347,14 @@ public class LogManager {
} }
} }
} }
if (max != null) if (max != null) {
log.setMinimumPriority(max.getLimit()); log.setMinimumPriority(max.getLimit());
else } else {
//if (_log != null)
// _log.debug("The log for " + log.getClass() + " has no matching limits");
log.setMinimumPriority(_defaultLimit); log.setMinimumPriority(_defaultLimit);
} }
}
private List getLimits(Log log) { private List getLimits(Log log) {
ArrayList limits = new ArrayList(); ArrayList limits = new ArrayList();
@ -373,10 +401,11 @@ public class LogManager {
} }
public static void main(String args[]) { public static void main(String args[]) {
Log l1 = new Log("test.1"); I2PAppContext ctx = new I2PAppContext();
Log l2 = new Log("test.2"); Log l1 = ctx.logManager().getLog("test.1");
Log l21 = new Log("test.2.1"); Log l2 = ctx.logManager().getLog("test.2");
Log l = new Log("test"); Log l21 = ctx.logManager().getLog("test.2.1");
Log l = ctx.logManager().getLog("test");
l.debug("this should fail"); l.debug("this should fail");
l.info("this should pass"); l.info("this should pass");
l1.warn("this should pass"); l1.warn("this should pass");

View File

@ -26,13 +26,13 @@ class LogRecordFormatter {
private final static int MAX_THREAD_LENGTH = 12; private final static int MAX_THREAD_LENGTH = 12;
private final static int MAX_PRIORITY_LENGTH = 5; 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(); StringBuffer buf = new StringBuffer();
char format[] = LogManager.getInstance()._getFormat(); char format[] = manager._getFormat();
for (int i = 0; i < format.length; ++i) { for (int i = 0; i < format.length; ++i) {
switch ((int) format[i]) { switch ((int) format[i]) {
case (int) LogManager.DATE: case (int) LogManager.DATE:
buf.append(getWhen(rec)); buf.append(getWhen(manager, rec));
break; break;
case (int) LogManager.CLASS: case (int) LogManager.CLASS:
buf.append(getWhere(rec)); buf.append(getWhere(rec));
@ -71,8 +71,8 @@ class LogRecordFormatter {
return toString(logRecord.getThreadName(), MAX_THREAD_LENGTH); return toString(logRecord.getThreadName(), MAX_THREAD_LENGTH);
} }
private static String getWhen(LogRecord logRecord) { private static String getWhen(LogManager manager, LogRecord logRecord) {
return LogManager.getInstance()._getDateFormat().format(new Date(logRecord.getDate())); return manager._getDateFormat().format(new Date(logRecord.getDate()));
} }
private static String getPriority(LogRecord rec) { private static String getPriority(LogRecord rec) {

View File

@ -29,9 +29,15 @@ class LogWriter implements Runnable {
private int _rotationNum = -1; private int _rotationNum = -1;
private String _logFilenamePattern; private String _logFilenamePattern;
private File _currentFile; private File _currentFile;
private LogManager _manager;
private boolean _write; private boolean _write;
private LogWriter() {}
public LogWriter(LogManager manager) {
_manager = manager;
}
public void stopWriting() { public void stopWriting() {
_write = false; _write = false;
} }
@ -46,7 +52,7 @@ class LogWriter implements Runnable {
public void flushRecords() { public void flushRecords() {
try { try {
List records = LogManager.getInstance()._removeAll(); List records = _manager._removeAll();
for (int i = 0; i < records.size(); i++) { for (int i = 0; i < records.size(); i++) {
LogRecord rec = (LogRecord) records.get(i); LogRecord rec = (LogRecord) records.get(i);
writeRecord(rec); writeRecord(rec);
@ -68,19 +74,19 @@ class LogWriter implements Runnable {
} }
long now = Clock.getInstance().now(); long now = Clock.getInstance().now();
if (now - _lastReadConfig > CONFIG_READ_ITERVAL) { if (now - _lastReadConfig > CONFIG_READ_ITERVAL) {
LogManager.getInstance().rereadConfig(); _manager.rereadConfig();
_lastReadConfig = now; _lastReadConfig = now;
} }
} }
private void writeRecord(LogRecord rec) { private void writeRecord(LogRecord rec) {
String val = LogRecordFormatter.formatRecord(rec); String val = LogRecordFormatter.formatRecord(_manager, rec);
writeRecord(val); 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 // we always add to the console buffer, but only sometimes write to stdout
LogConsoleBuffer.getInstance().add(val); _manager.getBuffer().add(val);
if (LogManager.getInstance().displayOnScreen()) { if (_manager.displayOnScreen()) {
System.out.print(val); System.out.print(val);
} }
} }
@ -98,7 +104,7 @@ class LogWriter implements Runnable {
System.err.println("Error writing record, disk full?"); System.err.println("Error writing record, disk full?");
t.printStackTrace(); t.printStackTrace();
} }
if (_numBytesInCurrentFile >= LogManager.getInstance()._getFileSize()) { if (_numBytesInCurrentFile >= _manager._getFileSize()) {
rotateFile(); rotateFile();
} }
} }
@ -108,7 +114,7 @@ class LogWriter implements Runnable {
* *
*/ */
private void rotateFile() { private void rotateFile() {
String pattern = LogManager.getInstance()._getBaseLogfilename(); String pattern = _manager._getBaseLogfilename();
File f = getNextFile(pattern); File f = getNextFile(pattern);
_currentFile = f; _currentFile = f;
_numBytesInCurrentFile = 0; _numBytesInCurrentFile = 0;
@ -129,7 +135,7 @@ class LogWriter implements Runnable {
if (pattern.indexOf('#') < 0) { if (pattern.indexOf('#') < 0) {
return new File(pattern); return new File(pattern);
} else { } else {
int max = LogManager.getInstance()._getRotationLimit(); int max = _manager._getRotationLimit();
if (_rotationNum == -1) { if (_rotationNum == -1) {
return getFirstFile(pattern, max); return getFirstFile(pattern, max);
} else { } else {

View File

@ -10,6 +10,7 @@ package net.i2p.util;
*/ */
import java.security.SecureRandom; import java.security.SecureRandom;
import net.i2p.I2PAppContext;
/** /**
* Singleton for whatever PRNG i2p uses. * Singleton for whatever PRNG i2p uses.
@ -17,14 +18,14 @@ import java.security.SecureRandom;
* @author jrandom * @author jrandom
*/ */
public class RandomSource extends SecureRandom { public class RandomSource extends SecureRandom {
private final static RandomSource _random = new RandomSource(); private Log _log;
private RandomSource() { public RandomSource(I2PAppContext context) {
super(); super();
_log = context.logManager().getLog(RandomSource.class);
} }
public static RandomSource getInstance() { public static RandomSource getInstance() {
return _random; return I2PAppContext.getGlobalContext().random();
} }
/** /**

View File

@ -31,8 +31,10 @@ package net.i2p.crypto;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.I2PAppContext;
public class AES256Bench { public class AES256Bench {
private static I2PAppContext _context = new I2PAppContext();
public static void main(String args[]) { public static void main(String args[]) {
char[] cplain = { char[] cplain = {
@ -70,8 +72,8 @@ public class AES256Bench {
iv[x] = (byte)civ[x]; iv[x] = (byte)civ[x];
} }
byte[] e = AESEngine.getInstance().encrypt(plain, key, iv); byte[] e = _context.AESEngine().encrypt(plain, key, iv);
byte[] d = AESEngine.getInstance().decrypt(e, key, iv); byte[] d = _context.AESEngine().decrypt(e, key, iv);
boolean same = true; boolean same = true;
for (int x = 0; x < d.length; x++) { for (int x = 0; x < d.length; x++) {
if (plain[x] != d[x]) { if (plain[x] != d[x]) {
@ -82,8 +84,8 @@ public class AES256Bench {
System.out.println("Standard test D(E(value)) == value? " + same); System.out.println("Standard test D(E(value)) == value? " + same);
plain = "1234567890123456".getBytes(); plain = "1234567890123456".getBytes();
e = AESEngine.getInstance().encrypt(plain, key, iv); e = _context.AESEngine().encrypt(plain, key, iv);
d = AESEngine.getInstance().decrypt(e, key, iv); d = _context.AESEngine().decrypt(e, key, iv);
same = DataHelper.eq(plain, d); same = DataHelper.eq(plain, d);
System.out.println("Different value test D(E(value)) == value? " + same); System.out.println("Different value test D(E(value)) == value? " + same);
@ -102,9 +104,9 @@ public class AES256Bench {
message[i] = (byte)((i%26)+'a'); message[i] = (byte)((i%26)+'a');
for (int x = 0; x < times; x++) { for (int x = 0; x < times; x++) {
long startencrypt = System.currentTimeMillis(); long startencrypt = System.currentTimeMillis();
e = AESEngine.getInstance().encrypt(message, key, iv); e = _context.AESEngine().encrypt(message, key, iv);
long endencryptstartdecrypt = System.currentTimeMillis(); long endencryptstartdecrypt = System.currentTimeMillis();
d = AESEngine.getInstance().decrypt(e, key, iv); d = _context.AESEngine().decrypt(e, key, iv);
long enddecrypt = System.currentTimeMillis(); long enddecrypt = System.currentTimeMillis();
System.out.print("."); System.out.print(".");
encrypttime += endencryptstartdecrypt - startencrypt; encrypttime += endencryptstartdecrypt - startencrypt;

View File

@ -8,6 +8,7 @@ package net.i2p.crypto;
* *
*/ */
import net.i2p.I2PAppContext;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.data.PublicKey; import net.i2p.data.PublicKey;
@ -25,6 +26,10 @@ import java.util.HashSet;
class ElGamalAESEngineTest { class ElGamalAESEngineTest {
private final static Log _log = new Log(ElGamalAESEngineTest.class); private final static Log _log = new Log(ElGamalAESEngineTest.class);
private I2PAppContext _context;
public ElGamalAESEngineTest(I2PAppContext ctx) {
_context = ctx;
}
public void runRoundtripTest() { public void runRoundtripTest() {
try { try {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
@ -33,11 +38,11 @@ class ElGamalAESEngineTest {
String msg = "Hello world"; String msg = "Hello world";
Set toBeDelivered = new HashSet(); Set toBeDelivered = new HashSet();
SessionKey key = SessionKeyManager.getInstance().getCurrentKey(pubKey); SessionKey key = _context.sessionKeyManager().getCurrentKey(pubKey);
if (key == null) if (key == null)
key = SessionKeyManager.getInstance().createSession(pubKey); key = _context.sessionKeyManager().createSession(pubKey);
byte[] encrypted = ElGamalAESEngine.encrypt(msg.getBytes(), pubKey, key, 64); byte[] encrypted = _context.elGamalAESEngine().encrypt(msg.getBytes(), pubKey, key, 64);
byte[] decrypted = ElGamalAESEngine.decrypt(encrypted, privKey); byte[] decrypted = _context.elGamalAESEngine().decrypt(encrypted, privKey);
if (decrypted == null) if (decrypted == null)
throw new Exception("Failed to decrypt"); throw new Exception("Failed to decrypt");
String read = new String(decrypted); String read = new String(decrypted);
@ -85,14 +90,14 @@ class ElGamalAESEngineTest {
private long[] runMessage(PublicKey pubKey, PrivateKey privKey) throws Exception { private long[] runMessage(PublicKey pubKey, PrivateKey privKey) throws Exception {
byte[] msg = new byte[400]; byte[] msg = new byte[400];
RandomSource.getInstance().nextBytes(msg); RandomSource.getInstance().nextBytes(msg);
SessionKey key = SessionKeyManager.getInstance().getCurrentKey(pubKey); SessionKey key = _context.sessionKeyManager().getCurrentKey(pubKey);
if (key == null) if (key == null)
key = SessionKeyManager.getInstance().createSession(pubKey); key = _context.sessionKeyManager().createSession(pubKey);
long beforeE = Clock.getInstance().now(); long beforeE = Clock.getInstance().now();
byte[] encrypted = ElGamalAESEngine.encrypt(msg, pubKey, key, 1024); byte[] encrypted = _context.elGamalAESEngine().encrypt(msg, pubKey, key, 1024);
long afterE = Clock.getInstance().now(); long afterE = Clock.getInstance().now();
byte[] decrypted = ElGamalAESEngine.decrypt(encrypted, privKey); byte[] decrypted = _context.elGamalAESEngine().decrypt(encrypted, privKey);
long afterD = Clock.getInstance().now(); long afterD = Clock.getInstance().now();
if (!DataHelper.eq(msg, decrypted)) { if (!DataHelper.eq(msg, decrypted)) {
_log.error("WTF, D(E(val)) != val"); _log.error("WTF, D(E(val)) != val");
@ -114,11 +119,11 @@ class ElGamalAESEngineTest {
String msg = "Hello world"; String msg = "Hello world";
byte encrypted[] = ElGamalAESEngine.encryptAESBlock(msg.getBytes(), sessionKey, iv, null, null, 64); byte encrypted[] = _context.elGamalAESEngine().encryptAESBlock(msg.getBytes(), sessionKey, iv, null, null, 64);
_log.debug("** Encryption complete. Beginning decryption"); _log.debug("** Encryption complete. Beginning decryption");
Set foundTags = new HashSet(); Set foundTags = new HashSet();
SessionKey foundKey = new SessionKey(); SessionKey foundKey = new SessionKey();
byte decrypted[] = ElGamalAESEngine.decryptAESBlock(encrypted, sessionKey, iv, null, foundTags, foundKey); byte decrypted[] = _context.elGamalAESEngine().decryptAESBlock(encrypted, sessionKey, iv, null, foundTags, foundKey);
if (decrypted == null) throw new Exception("Decryption failed"); if (decrypted == null) throw new Exception("Decryption failed");
String read = new String(decrypted); String read = new String(decrypted);
_log.debug("read: " + read); _log.debug("read: " + read);
@ -140,8 +145,8 @@ class ElGamalAESEngineTest {
String msg = "Hello world01234012345678901234501234567890123450123456789012345"; String msg = "Hello world01234012345678901234501234567890123450123456789012345";
h = SHA256Generator.getInstance().calculateHash(msg.getBytes()); h = SHA256Generator.getInstance().calculateHash(msg.getBytes());
_log.debug("Hash of entire aes block before encryption: \n" + DataHelper.toString(h.getData(), 32)); _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 aesEncr[] = _context.AESEngine().encrypt(msg.getBytes(), sessionKey, iv);
byte aesDecr[] = AESEngine.getInstance().decrypt(aesEncr, sessionKey, iv); byte aesDecr[] = _context.AESEngine().decrypt(aesEncr, sessionKey, iv);
h = SHA256Generator.getInstance().calculateHash(aesDecr); h = SHA256Generator.getInstance().calculateHash(aesDecr);
_log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32)); _log.debug("Hash of entire aes block after decryption: \n" + DataHelper.toString(h.getData(), 32));
if (msg.equals(new String(aesDecr))) { if (msg.equals(new String(aesDecr))) {
@ -173,13 +178,13 @@ class ElGamalAESEngineTest {
byte preIV[] = new byte[32]; byte preIV[] = new byte[32];
RandomSource.getInstance().nextBytes(preIV); RandomSource.getInstance().nextBytes(preIV);
elgSrc.write(preIV); elgSrc.write(preIV);
// byte rnd[] = new byte[191]; // byte rnd[] = new byte[191];
// RandomSource.getInstance().nextBytes(rnd); // RandomSource.getInstance().nextBytes(rnd);
// elgSrc.write(rnd); // elgSrc.write(rnd);
elgSrc.flush(); elgSrc.flush();
byte elgEncr[] = ElGamalEngine.getInstance().encrypt(elgSrc.toByteArray(), pubKey); byte elgEncr[] = _context.elGamalEngine().encrypt(elgSrc.toByteArray(), pubKey);
byte elgDecr[] = ElGamalEngine.getInstance().decrypt(elgEncr, privKey); byte elgDecr[] = _context.elGamalEngine().decrypt(elgEncr, privKey);
ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr); ByteArrayInputStream bais = new ByteArrayInputStream(elgDecr);
SessionKey nk = new SessionKey(); SessionKey nk = new SessionKey();
@ -215,7 +220,8 @@ class ElGamalAESEngineTest {
} }
public static void main(String args[]) { public static void main(String args[]) {
ElGamalAESEngineTest tst = new ElGamalAESEngineTest(); I2PAppContext context = new I2PAppContext();
ElGamalAESEngineTest tst = new ElGamalAESEngineTest(context);
Object o = YKGenerator.class; Object o = YKGenerator.class;
try { Thread.sleep(120*1000); } catch (InterruptedException ie) {} try { Thread.sleep(120*1000); } catch (InterruptedException ie) {}
@ -229,7 +235,7 @@ class ElGamalAESEngineTest {
// test throughput // test throughput
tst.runLoopTest(5); tst.runLoopTest(5);
net.i2p.stat.SimpleStatDumper.dumpStats(Log.CRIT); net.i2p.stat.SimpleStatDumper.dumpStats(context, Log.CRIT);
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
} }
} }

View File

@ -32,8 +32,10 @@ package net.i2p.crypto;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.PrivateKey; import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey; import net.i2p.data.PublicKey;
import net.i2p.I2PAppContext;
public class ElGamalBench { public class ElGamalBench {
private static I2PAppContext _context = new I2PAppContext();
public static void main(String args[]) { public static void main(String args[]) {
int times = 100; int times = 100;
long keygentime = 0; long keygentime = 0;
@ -56,9 +58,9 @@ public class ElGamalBench {
PrivateKey privkey = (PrivateKey)keys[1]; PrivateKey privkey = (PrivateKey)keys[1];
long endkeys = System.currentTimeMillis(); long endkeys = System.currentTimeMillis();
long startencrypt = System.currentTimeMillis(); long startencrypt = System.currentTimeMillis();
byte[] e = ElGamalEngine.getInstance().encrypt(message, pubkey); byte[] e = _context.elGamalEngine().encrypt(message, pubkey);
long endencryptstartdecrypt = System.currentTimeMillis(); long endencryptstartdecrypt = System.currentTimeMillis();
byte[] d = ElGamalEngine.getInstance().decrypt(e, privkey); byte[] d = _context.elGamalEngine().decrypt(e, privkey);
long enddecrypt = System.currentTimeMillis(); long enddecrypt = System.currentTimeMillis();
System.out.print("."); System.out.print(".");
keygentime += endkeys - startkeys; keygentime += endkeys - startkeys;

View File

@ -16,6 +16,7 @@ import net.i2p.data.DataHelper;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.I2PAppContext;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -45,6 +46,7 @@ import java.util.Set;
*/ */
public class SessionEncryptionTest { public class SessionEncryptionTest {
private final static Log _log = new Log(SessionEncryptionTest.class); private final static Log _log = new Log(SessionEncryptionTest.class);
private static I2PAppContext _context = new I2PAppContext();
public static void main(String args[]) { public static void main(String args[]) {
SessionEncryptionTest test = new SessionEncryptionTest(); SessionEncryptionTest test = new SessionEncryptionTest();
try { try {
@ -67,20 +69,20 @@ public class SessionEncryptionTest {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey)keys[0]; PublicKey pubKey = (PublicKey)keys[0];
PrivateKey privKey = (PrivateKey)keys[1]; PrivateKey privKey = (PrivateKey)keys[1];
SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); SessionKey curKey = _context.sessionKeyManager().createSession(pubKey);
byte[] msg1 = "msg 1".getBytes(); byte[] msg1 = "msg 1".getBytes();
byte[] msg2 = "msg 2".getBytes(); byte[] msg2 = "msg 2".getBytes();
byte emsg1[] = ElGamalAESEngine.encrypt(msg1, pubKey, curKey, 64); byte emsg1[] = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, 64);
byte dmsg1[] = ElGamalAESEngine.decrypt(emsg1, privKey); byte dmsg1[] = _context.elGamalAESEngine().decrypt(emsg1, privKey);
if (DataHelper.eq(dmsg1, msg1)) if (DataHelper.eq(dmsg1, msg1))
_log.info("PASSED: No sessions msg 1"); _log.info("PASSED: No sessions msg 1");
else else
_log.error("FAILED: No sessions msg 1"); _log.error("FAILED: No sessions msg 1");
byte emsg2[] = ElGamalAESEngine.encrypt(msg2, pubKey, curKey, 64); byte emsg2[] = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, 64);
byte dmsg2[] = ElGamalAESEngine.decrypt(emsg2, privKey); byte dmsg2[] = _context.elGamalAESEngine().decrypt(emsg2, privKey);
if (DataHelper.eq(dmsg2, msg2)) if (DataHelper.eq(dmsg2, msg2))
_log.info("PASSED: No sessions msg 2"); _log.info("PASSED: No sessions msg 2");
else else
@ -99,7 +101,7 @@ public class SessionEncryptionTest {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey)keys[0]; PublicKey pubKey = (PublicKey)keys[0];
PrivateKey privKey = (PrivateKey)keys[1]; PrivateKey privKey = (PrivateKey)keys[1];
SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); SessionKey curKey = _context.sessionKeyManager().createSession(pubKey);
SessionTag tag1 = new SessionTag(true); SessionTag tag1 = new SessionTag(true);
SessionTag tag2 = new SessionTag(true); SessionTag tag2 = new SessionTag(true);
@ -120,8 +122,8 @@ public class SessionEncryptionTest {
byte[] msg4 = "msg 4".getBytes(); byte[] msg4 = "msg 4".getBytes();
byte[] msg5 = "msg 5".getBytes(); byte[] msg5 = "msg 5".getBytes();
byte emsg1[] = ElGamalAESEngine.encrypt(msg1, pubKey, curKey, firstTags, 64); byte emsg1[] = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, firstTags, 64);
byte dmsg1[] = ElGamalAESEngine.decrypt(emsg1, privKey); byte dmsg1[] = _context.elGamalAESEngine().decrypt(emsg1, privKey);
if (DataHelper.eq(dmsg1, msg1)) if (DataHelper.eq(dmsg1, msg1))
_log.info("PASSED: Sessions msg 1"); _log.info("PASSED: Sessions msg 1");
else { else {
@ -129,17 +131,17 @@ public class SessionEncryptionTest {
return; return;
} }
SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, firstTags); _context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags);
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
SessionTag curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 2"); _log.error("Not able to consume next tag for message 2");
return; return;
} }
byte emsg2[] = ElGamalAESEngine.encrypt(msg2, pubKey, curKey, null, curTag, 64); byte emsg2[] = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, null, curTag, 64);
byte dmsg2[] = ElGamalAESEngine.decrypt(emsg2, privKey); byte dmsg2[] = _context.elGamalAESEngine().decrypt(emsg2, privKey);
if (DataHelper.eq(dmsg2, msg2)) if (DataHelper.eq(dmsg2, msg2))
_log.info("PASSED: Sessions msg 2"); _log.info("PASSED: Sessions msg 2");
else { else {
@ -147,8 +149,8 @@ public class SessionEncryptionTest {
return; return;
} }
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 3"); _log.error("Not able to consume next tag for message 3");
@ -159,8 +161,8 @@ public class SessionEncryptionTest {
return; return;
} }
byte emsg3[] = ElGamalAESEngine.encrypt(msg3, pubKey, curKey, secondTags, curTag, 64); byte emsg3[] = _context.elGamalAESEngine().encrypt(msg3, pubKey, curKey, secondTags, curTag, 64);
byte dmsg3[] = ElGamalAESEngine.decrypt(emsg3, privKey); byte dmsg3[] = _context.elGamalAESEngine().decrypt(emsg3, privKey);
if (DataHelper.eq(dmsg3, msg3)) if (DataHelper.eq(dmsg3, msg3))
_log.info("PASSED: Sessions msg 3"); _log.info("PASSED: Sessions msg 3");
else { else {
@ -168,10 +170,10 @@ public class SessionEncryptionTest {
return; return;
} }
SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, secondTags); _context.sessionKeyManager().tagsDelivered(pubKey, curKey, secondTags);
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 4"); _log.error("Not able to consume next tag for message 4");
@ -182,8 +184,8 @@ public class SessionEncryptionTest {
return; return;
} }
byte emsg4[] = ElGamalAESEngine.encrypt(msg4, pubKey, curKey, null, curTag, 64); byte emsg4[] = _context.elGamalAESEngine().encrypt(msg4, pubKey, curKey, null, curTag, 64);
byte dmsg4[] = ElGamalAESEngine.decrypt(emsg4, privKey); byte dmsg4[] = _context.elGamalAESEngine().decrypt(emsg4, privKey);
if (DataHelper.eq(dmsg4, msg4)) if (DataHelper.eq(dmsg4, msg4))
_log.info("PASSED: Sessions msg 4"); _log.info("PASSED: Sessions msg 4");
else { else {
@ -191,8 +193,8 @@ public class SessionEncryptionTest {
return; return;
} }
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 5"); _log.error("Not able to consume next tag for message 5");
@ -203,8 +205,8 @@ public class SessionEncryptionTest {
return; return;
} }
byte emsg5[] = ElGamalAESEngine.encrypt(msg5, pubKey, curKey, null, curTag, 64); byte emsg5[] = _context.elGamalAESEngine().encrypt(msg5, pubKey, curKey, null, curTag, 64);
byte dmsg5[] = ElGamalAESEngine.decrypt(emsg5, privKey); byte dmsg5[] = _context.elGamalAESEngine().decrypt(emsg5, privKey);
if (DataHelper.eq(dmsg5, msg5)) if (DataHelper.eq(dmsg5, msg5))
_log.info("PASSED: Sessions msg 5"); _log.info("PASSED: Sessions msg 5");
else { else {
@ -225,7 +227,7 @@ public class SessionEncryptionTest {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey)keys[0]; PublicKey pubKey = (PublicKey)keys[0];
PrivateKey privKey = (PrivateKey)keys[1]; PrivateKey privKey = (PrivateKey)keys[1];
SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); SessionKey curKey = _context.sessionKeyManager().createSession(pubKey);
SessionKey nextKey = KeyGenerator.getInstance().generateSessionKey(); SessionKey nextKey = KeyGenerator.getInstance().generateSessionKey();
SessionTag tag1 = new SessionTag(true); SessionTag tag1 = new SessionTag(true);
@ -247,8 +249,8 @@ public class SessionEncryptionTest {
byte[] msg4 = "msg 4".getBytes(); byte[] msg4 = "msg 4".getBytes();
byte[] msg5 = "msg 5".getBytes(); byte[] msg5 = "msg 5".getBytes();
byte emsg1[] = ElGamalAESEngine.encrypt(msg1, pubKey, curKey, firstTags, 64); byte emsg1[] = _context.elGamalAESEngine().encrypt(msg1, pubKey, curKey, firstTags, 64);
byte dmsg1[] = ElGamalAESEngine.decrypt(emsg1, privKey); byte dmsg1[] = _context.elGamalAESEngine().decrypt(emsg1, privKey);
if (DataHelper.eq(dmsg1, msg1)) if (DataHelper.eq(dmsg1, msg1))
_log.info("PASSED: Sessions msg 1"); _log.info("PASSED: Sessions msg 1");
else { else {
@ -256,17 +258,17 @@ public class SessionEncryptionTest {
return; return;
} }
SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, firstTags); _context.sessionKeyManager().tagsDelivered(pubKey, curKey, firstTags);
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
SessionTag curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 2"); _log.error("Not able to consume next tag for message 2");
return; return;
} }
byte emsg2[] = ElGamalAESEngine.encrypt(msg2, pubKey, curKey, null, curTag, 64); byte emsg2[] = _context.elGamalAESEngine().encrypt(msg2, pubKey, curKey, null, curTag, 64);
byte dmsg2[] = ElGamalAESEngine.decrypt(emsg2, privKey); byte dmsg2[] = _context.elGamalAESEngine().decrypt(emsg2, privKey);
if (DataHelper.eq(dmsg2, msg2)) if (DataHelper.eq(dmsg2, msg2))
_log.info("PASSED: Sessions msg 2"); _log.info("PASSED: Sessions msg 2");
else { else {
@ -274,8 +276,8 @@ public class SessionEncryptionTest {
return; return;
} }
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 3"); _log.error("Not able to consume next tag for message 3");
@ -286,8 +288,8 @@ public class SessionEncryptionTest {
return; return;
} }
byte emsg3[] = ElGamalAESEngine.encrypt(msg3, pubKey, curKey, secondTags, curTag, nextKey, 64); byte emsg3[] = _context.elGamalAESEngine().encrypt(msg3, pubKey, curKey, secondTags, curTag, nextKey, 64);
byte dmsg3[] = ElGamalAESEngine.decrypt(emsg3, privKey); byte dmsg3[] = _context.elGamalAESEngine().decrypt(emsg3, privKey);
if (DataHelper.eq(dmsg3, msg3)) if (DataHelper.eq(dmsg3, msg3))
_log.info("PASSED: Sessions msg 3"); _log.info("PASSED: Sessions msg 3");
else { else {
@ -295,10 +297,10 @@ public class SessionEncryptionTest {
return; return;
} }
SessionKeyManager.getInstance().tagsDelivered(pubKey, nextKey, secondTags); // note nextKey not curKey _context.sessionKeyManager().tagsDelivered(pubKey, nextKey, secondTags); // note nextKey not curKey
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 4"); _log.error("Not able to consume next tag for message 4");
@ -309,8 +311,8 @@ public class SessionEncryptionTest {
return; return;
} }
byte emsg4[] = ElGamalAESEngine.encrypt(msg4, pubKey, curKey, null, curTag, 64); byte emsg4[] = _context.elGamalAESEngine().encrypt(msg4, pubKey, curKey, null, curTag, 64);
byte dmsg4[] = ElGamalAESEngine.decrypt(emsg4, privKey); byte dmsg4[] = _context.elGamalAESEngine().decrypt(emsg4, privKey);
if (DataHelper.eq(dmsg4, msg4)) if (DataHelper.eq(dmsg4, msg4))
_log.info("PASSED: Sessions msg 4"); _log.info("PASSED: Sessions msg 4");
else { else {
@ -318,8 +320,8 @@ public class SessionEncryptionTest {
return; return;
} }
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
if (curTag == null) { if (curTag == null) {
_log.error("Not able to consume next tag for message 5"); _log.error("Not able to consume next tag for message 5");
@ -330,8 +332,8 @@ public class SessionEncryptionTest {
return; return;
} }
byte emsg5[] = ElGamalAESEngine.encrypt(msg5, pubKey, curKey, null, curTag, 64); byte emsg5[] = _context.elGamalAESEngine().encrypt(msg5, pubKey, curKey, null, curTag, 64);
byte dmsg5[] = ElGamalAESEngine.decrypt(emsg5, privKey); byte dmsg5[] = _context.elGamalAESEngine().decrypt(emsg5, privKey);
if (DataHelper.eq(dmsg5, msg5)) if (DataHelper.eq(dmsg5, msg5))
_log.info("PASSED: Sessions msg 5"); _log.info("PASSED: Sessions msg 5");
else { else {
@ -358,15 +360,15 @@ public class SessionEncryptionTest {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey)keys[0]; PublicKey pubKey = (PublicKey)keys[0];
PrivateKey privKey = (PrivateKey)keys[1]; PrivateKey privKey = (PrivateKey)keys[1];
SessionKey curKey = SessionKeyManager.getInstance().createSession(pubKey); SessionKey curKey = _context.sessionKeyManager().createSession(pubKey);
for (int i = 0; i < numMsgs; i++) { for (int i = 0; i < numMsgs; i++) {
Set tags = null; Set tags = null;
SessionKey nextKey = null; SessionKey nextKey = null;
curKey = SessionKeyManager.getInstance().getCurrentKey(pubKey); curKey = _context.sessionKeyManager().getCurrentKey(pubKey);
SessionTag curTag = SessionKeyManager.getInstance().consumeNextAvailableTag(pubKey, curKey); SessionTag curTag = _context.sessionKeyManager().consumeNextAvailableTag(pubKey, curKey);
int availTags = SessionKeyManager.getInstance().getAvailableTags(pubKey, curKey); int availTags = _context.sessionKeyManager().getAvailableTags(pubKey, curKey);
if ((availTags < 1)) { if ((availTags < 1)) {
tags = generateNewTags(50); tags = generateNewTags(50);
_log.info("Generating new tags"); _log.info("Generating new tags");
@ -378,8 +380,8 @@ public class SessionEncryptionTest {
byte[] msg = ("msg " + i).getBytes(); byte[] msg = ("msg " + i).getBytes();
byte emsg[] = ElGamalAESEngine.encrypt(msg, pubKey, curKey, tags, curTag, nextKey, 64); byte emsg[] = _context.elGamalAESEngine().encrypt(msg, pubKey, curKey, tags, curTag, nextKey, 64);
byte dmsg[] = ElGamalAESEngine.decrypt(emsg, privKey); byte dmsg[] = _context.elGamalAESEngine().decrypt(emsg, privKey);
if (DataHelper.eq(dmsg, msg)) if (DataHelper.eq(dmsg, msg))
_log.info("PASSED: Long session msg " + i); _log.info("PASSED: Long session msg " + i);
else { else {
@ -389,9 +391,9 @@ public class SessionEncryptionTest {
if ( (tags != null) && (tags.size() > 0) ) { if ( (tags != null) && (tags.size() > 0) ) {
if (nextKey == null) { if (nextKey == null) {
SessionKeyManager.getInstance().tagsDelivered(pubKey, curKey, tags); _context.sessionKeyManager().tagsDelivered(pubKey, curKey, tags);
} else { } else {
SessionKeyManager.getInstance().tagsDelivered(pubKey, nextKey, tags); _context.sessionKeyManager().tagsDelivered(pubKey, nextKey, tags);
} }
} }
} }

View File

@ -15,6 +15,7 @@ import java.io.InputStream;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataStructure; import net.i2p.data.DataStructure;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Utility class for wrapping data structure tests * Utility class for wrapping data structure tests
@ -23,6 +24,7 @@ import net.i2p.util.Log;
*/ */
public abstract class StructureTest implements TestDataGenerator, TestDataPrinter { public abstract class StructureTest implements TestDataGenerator, TestDataPrinter {
private static final Log _log = new Log(StructureTest.class); private static final Log _log = new Log(StructureTest.class);
protected static I2PAppContext _context = I2PAppContext.getGlobalContext();
public abstract DataStructure createDataStructure() throws DataFormatException; public abstract DataStructure createDataStructure() throws DataFormatException;
public abstract DataStructure createStructureToRead(); public abstract DataStructure createStructureToRead();

View File

@ -15,6 +15,7 @@ import java.io.InputStream;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines a message containing arbitrary bytes of data * Defines a message containing arbitrary bytes of data
@ -26,7 +27,8 @@ public class DataMessage extends I2NPMessageImpl {
public final static int MESSAGE_TYPE = 20; public final static int MESSAGE_TYPE = 20;
private byte _data[]; private byte _data[];
public DataMessage() { public DataMessage(I2PAppContext context) {
super(context);
_data = null; _data = null;
} }

View File

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

View File

@ -21,6 +21,7 @@ import net.i2p.data.Hash;
import net.i2p.data.RouterInfo; import net.i2p.data.RouterInfo;
import net.i2p.data.TunnelId; import net.i2p.data.TunnelId;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines the message a router sends to another router to search for a * Defines the message a router sends to another router to search for a
@ -36,7 +37,8 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
private TunnelId _replyTunnel; private TunnelId _replyTunnel;
private Set _dontIncludePeers; private Set _dontIncludePeers;
public DatabaseLookupMessage() { public DatabaseLookupMessage(I2PAppContext context) {
super(context);
setSearchKey(null); setSearchKey(null);
setFrom(null); setFrom(null);
setDontIncludePeers(null); setDontIncludePeers(null);

View File

@ -21,6 +21,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.RouterInfo; import net.i2p.data.RouterInfo;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines the message a router sends to another router in response to a * Defines the message a router sends to another router in response to a
@ -36,7 +37,8 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
private List _routerInfoStructures; private List _routerInfoStructures;
private Hash _from; private Hash _from;
public DatabaseSearchReplyMessage() { public DatabaseSearchReplyMessage(I2PAppContext context) {
super(context);
setSearchKey(null); setSearchKey(null);
_routerInfoStructures = new ArrayList(); _routerInfoStructures = new ArrayList();
setFromHash(null); setFromHash(null);

View File

@ -19,6 +19,7 @@ import net.i2p.data.Hash;
import net.i2p.data.LeaseSet; import net.i2p.data.LeaseSet;
import net.i2p.data.RouterInfo; import net.i2p.data.RouterInfo;
import net.i2p.util.Log; 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
@ -37,7 +38,8 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
public final static int KEY_TYPE_ROUTERINFO = 0; public final static int KEY_TYPE_ROUTERINFO = 0;
public final static int KEY_TYPE_LEASESET = 1; public final static int KEY_TYPE_LEASESET = 1;
public DatabaseStoreMessage() { public DatabaseStoreMessage(I2PAppContext context) {
super(context);
setValueType(-1); setValueType(-1);
setKey(null); setKey(null);
setLeaseSet(null); setLeaseSet(null);

View File

@ -16,6 +16,7 @@ import java.util.Date;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines the message sent back in reply to a message when requested, containing * Defines the message sent back in reply to a message when requested, containing
@ -29,7 +30,8 @@ public class DeliveryStatusMessage extends I2NPMessageImpl {
private long _id; private long _id;
private Date _arrival; private Date _arrival;
public DeliveryStatusMessage() { public DeliveryStatusMessage(I2PAppContext context) {
super(context);
setMessageId(-1); setMessageId(-1);
setArrival(null); setArrival(null);
} }

View File

@ -18,6 +18,7 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl; import net.i2p.data.DataStructureImpl;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.router.RouterContext;
/** /**
* Contains one deliverable message encrypted to a router along with instructions * Contains one deliverable message encrypted to a router along with instructions
@ -26,7 +27,8 @@ import net.i2p.util.Log;
* @author jrandom * @author jrandom
*/ */
public class GarlicClove extends DataStructureImpl { public class GarlicClove extends DataStructureImpl {
private final static Log _log = new Log(GarlicClove.class); private Log _log;
private RouterContext _context;
private DeliveryInstructions _instructions; private DeliveryInstructions _instructions;
private I2NPMessage _msg; private I2NPMessage _msg;
private long _cloveId; private long _cloveId;
@ -34,6 +36,7 @@ public class GarlicClove extends DataStructureImpl {
private Certificate _certificate; private Certificate _certificate;
private int _replyAction; private int _replyAction;
private SourceRouteBlock _sourceRouteBlock; private SourceRouteBlock _sourceRouteBlock;
private I2NPMessageHandler _handler;
/** No action requested with the source route block */ /** No action requested with the source route block */
public final static int ACTION_NONE = 0; public final static int ACTION_NONE = 0;
@ -50,7 +53,10 @@ public class GarlicClove extends DataStructureImpl {
*/ */
public final static int ACTION_MESSAGE_SPECIFIC = 2; public final static int ACTION_MESSAGE_SPECIFIC = 2;
public GarlicClove() { public GarlicClove(RouterContext context) {
_context = context;
_log = context.logManager().getLog(GarlicClove.class);
_handler = new I2NPMessageHandler(context);
setInstructions(null); setInstructions(null);
setData(null); setData(null);
setCloveId(-1); setCloveId(-1);
@ -80,7 +86,7 @@ public class GarlicClove extends DataStructureImpl {
_instructions.readBytes(in); _instructions.readBytes(in);
_log.debug("Read instructions: " + _instructions); _log.debug("Read instructions: " + _instructions);
try { try {
_msg = new I2NPMessageHandler().readMessage(in); _msg = _handler.readMessage(in);
} catch (I2NPMessageException ime) { } catch (I2NPMessageException ime) {
throw new DataFormatException("Unable to read the message from a garlic clove", ime); throw new DataFormatException("Unable to read the message from a garlic clove", ime);
} }

View File

@ -15,6 +15,7 @@ import java.io.InputStream;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines the wrapped garlic message * Defines the wrapped garlic message
@ -26,7 +27,8 @@ public class GarlicMessage extends I2NPMessageImpl {
public final static int MESSAGE_TYPE = 11; public final static int MESSAGE_TYPE = 11;
private byte[] _data; private byte[] _data;
public GarlicMessage() { public GarlicMessage(I2PAppContext context) {
super(context);
setData(null); setData(null);
} }

View File

@ -16,16 +16,21 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Handle messages from router to router * Handle messages from router to router
* *
*/ */
public class I2NPMessageHandler { public class I2NPMessageHandler {
private final static Log _log = new Log(I2NPMessageHandler.class); private Log _log;
private I2PAppContext _context;
private long _lastReadBegin; private long _lastReadBegin;
private long _lastReadEnd; 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. * Read an I2NPMessage from the stream and return the fully populated object.
@ -37,10 +42,10 @@ public class I2NPMessageHandler {
public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException { public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException {
try { try {
int type = (int)DataHelper.readLong(in, 1); int type = (int)DataHelper.readLong(in, 1);
_lastReadBegin = Clock.getInstance().now(); _lastReadBegin = System.currentTimeMillis();
I2NPMessage msg = createMessage(in, type); I2NPMessage msg = createMessage(in, type);
msg.readBytes(in, type); msg.readBytes(in, type);
_lastReadEnd = Clock.getInstance().now(); _lastReadEnd = System.currentTimeMillis();
return msg; return msg;
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the message", dfe); throw new I2NPMessageException("Error reading the message", dfe);
@ -53,28 +58,28 @@ public class I2NPMessageHandler {
* 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) { switch (type) {
case DatabaseStoreMessage.MESSAGE_TYPE: case DatabaseStoreMessage.MESSAGE_TYPE:
return new DatabaseStoreMessage(); return new DatabaseStoreMessage(_context);
case DatabaseLookupMessage.MESSAGE_TYPE: case DatabaseLookupMessage.MESSAGE_TYPE:
return new DatabaseLookupMessage(); return new DatabaseLookupMessage(_context);
case DatabaseSearchReplyMessage.MESSAGE_TYPE: case DatabaseSearchReplyMessage.MESSAGE_TYPE:
return new DatabaseSearchReplyMessage(); return new DatabaseSearchReplyMessage(_context);
case DeliveryStatusMessage.MESSAGE_TYPE: case DeliveryStatusMessage.MESSAGE_TYPE:
return new DeliveryStatusMessage(); return new DeliveryStatusMessage(_context);
case GarlicMessage.MESSAGE_TYPE: case GarlicMessage.MESSAGE_TYPE:
return new GarlicMessage(); return new GarlicMessage(_context);
case TunnelMessage.MESSAGE_TYPE: case TunnelMessage.MESSAGE_TYPE:
return new TunnelMessage(); return new TunnelMessage(_context);
case DataMessage.MESSAGE_TYPE: case DataMessage.MESSAGE_TYPE:
return new DataMessage(); return new DataMessage(_context);
case SourceRouteReplyMessage.MESSAGE_TYPE: case SourceRouteReplyMessage.MESSAGE_TYPE:
return new SourceRouteReplyMessage(); return new SourceRouteReplyMessage(_context);
case TunnelCreateMessage.MESSAGE_TYPE: case TunnelCreateMessage.MESSAGE_TYPE:
return new TunnelCreateMessage(); return new TunnelCreateMessage(_context);
case TunnelCreateStatusMessage.MESSAGE_TYPE: case TunnelCreateStatusMessage.MESSAGE_TYPE:
return new TunnelCreateStatusMessage(); return new TunnelCreateStatusMessage(_context);
default: default:
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message"); throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
} }
@ -82,7 +87,7 @@ public class I2NPMessageHandler {
public static void main(String args[]) { public static void main(String args[]) {
try { 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); System.out.println(msg);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -19,6 +19,7 @@ import net.i2p.data.DataStructureImpl;
import net.i2p.util.Clock; import net.i2p.util.Clock;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.RandomSource; import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/** /**
* Defines the base message implementation. * Defines the base message implementation.
@ -26,15 +27,18 @@ import net.i2p.util.RandomSource;
* @author jrandom * @author jrandom
*/ */
public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPMessage { 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 Date _expiration;
private long _uniqueId; private long _uniqueId;
public final static long DEFAULT_EXPIRATION_MS = 1*60*1000; // 1 minute by default public final static long DEFAULT_EXPIRATION_MS = 1*60*1000; // 1 minute by default
public I2NPMessageImpl() { public I2NPMessageImpl(I2PAppContext context) {
_expiration = new Date(Clock.getInstance().now() + DEFAULT_EXPIRATION_MS); _context = context;
_uniqueId = RandomSource.getInstance().nextInt(Integer.MAX_VALUE); _log = context.logManager().getLog(I2NPMessageImpl.class);
_expiration = new Date(_context.clock().now() + DEFAULT_EXPIRATION_MS);
_uniqueId = _context.random().nextInt(Integer.MAX_VALUE);
} }
/** /**

View File

@ -13,6 +13,7 @@ import java.io.InputStream;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.router.RouterContext;
/** /**
* The I2NPMessageReader reads an InputStream (using * The I2NPMessageReader reads an InputStream (using
@ -24,17 +25,20 @@ import net.i2p.util.Log;
* @author jrandom * @author jrandom
*/ */
public class I2NPMessageReader { public class I2NPMessageReader {
private final static Log _log = new Log(I2NPMessageReader.class); private Log _log;
private RouterContext _context;
private InputStream _stream; private InputStream _stream;
private I2NPMessageEventListener _listener; private I2NPMessageEventListener _listener;
private I2NPMessageReaderRunner _reader; private I2NPMessageReaderRunner _reader;
private Thread _readerThread; private Thread _readerThread;
public I2NPMessageReader(InputStream stream, I2NPMessageEventListener lsnr) { public I2NPMessageReader(RouterContext context, InputStream stream, I2NPMessageEventListener lsnr) {
this(stream, lsnr, "I2NP Reader"); this(context, stream, lsnr, "I2NP Reader");
} }
public I2NPMessageReader(InputStream stream, I2NPMessageEventListener lsnr, String name) { public I2NPMessageReader(RouterContext context, InputStream stream, I2NPMessageEventListener lsnr, String name) {
_context = context;
_log = context.logManager().getLog(I2NPMessageReader.class);
_stream = stream; _stream = stream;
setListener(lsnr); setListener(lsnr);
_reader = new I2NPMessageReaderRunner(); _reader = new I2NPMessageReaderRunner();
@ -99,7 +103,7 @@ public class I2NPMessageReader {
public I2NPMessageReaderRunner() { public I2NPMessageReaderRunner() {
_doRun = true; _doRun = true;
_stayAlive = true; _stayAlive = true;
_handler = new I2NPMessageHandler(); _handler = new I2NPMessageHandler(_context);
} }
public void pauseRunner() { _doRun = false; } public void pauseRunner() { _doRun = false; }
public void resumeRunner() { _doRun = true; } public void resumeRunner() { _doRun = true; }

View File

@ -26,6 +26,7 @@ import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey; import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag; import net.i2p.data.SessionTag;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
@ -126,7 +127,9 @@ public class SourceRouteBlock extends DataStructureImpl {
* *
* @throws DataFormatException if the data is invalid or could not be encrypted * @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 { public void setData(I2PAppContext ctx, DeliveryInstructions instructions,
long messageId, Certificate cert, long expiration,
PublicKey replyThrough) throws DataFormatException {
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(64); ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
@ -146,20 +149,23 @@ public class SourceRouteBlock extends DataStructureImpl {
if (instructions.getDelayRequested()) { if (instructions.getDelayRequested()) {
// always use a new key if we're delaying, since the reply block may not be used within the // always use a new key if we're delaying, since the reply block may not be used within the
// window of a session // window of a session
sessKey = KeyGenerator.getInstance().generateSessionKey(); sessKey = ctx.keyGenerator().generateSessionKey();
tag = null; tag = null;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Delay requested - creating a new session key"); _log.debug("Delay requested - creating a new session key");
} else { } else {
sessKey = SessionKeyManager.getInstance().getCurrentKey(replyThrough); sessKey = ctx.sessionKeyManager().getCurrentKey(replyThrough);
if (sessKey == null) { if (sessKey == null) {
sessKey = KeyGenerator.getInstance().generateSessionKey(); sessKey = ctx.keyGenerator().generateSessionKey();
tag = null; tag = null;
if (_log.shouldLog(Log.DEBUG))
_log.debug("No delay requested, but no session key is known"); _log.debug("No delay requested, but no session key is known");
} else { } else {
tag = SessionKeyManager.getInstance().consumeNextAvailableTag(replyThrough, sessKey); tag = ctx.sessionKeyManager().consumeNextAvailableTag(replyThrough, sessKey);
} }
} }
byte encData[] = ElGamalAESEngine.encrypt(baos.toByteArray(), replyThrough, sessKey, null, tag, paddedSize); byte encData[] = ctx.elGamalAESEngine().encrypt(baos.toByteArray(), replyThrough,
sessKey, null, tag, paddedSize);
setData(encData); setData(encData);
} catch (IOException ioe) { } catch (IOException ioe) {
throw new DataFormatException("Error writing out the source route block data", ioe); throw new DataFormatException("Error writing out the source route block data", ioe);

View File

@ -19,6 +19,7 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.PrivateKey; import net.i2p.data.PrivateKey;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines a message directed by a source route block to deliver a message to an * Defines a message directed by a source route block to deliver a message to an
@ -35,8 +36,11 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl {
private long _decryptedMessageId; private long _decryptedMessageId;
private Certificate _decryptedCertificate; private Certificate _decryptedCertificate;
private long _decryptedExpiration; private long _decryptedExpiration;
private I2NPMessageHandler _handler;
public SourceRouteReplyMessage() { public SourceRouteReplyMessage(I2PAppContext context) {
super(context);
_handler = new I2NPMessageHandler(context);
_encryptedHeader = null; _encryptedHeader = null;
_message = null; _message = null;
_decryptedInstructions = null; _decryptedInstructions = null;
@ -80,7 +84,7 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl {
if ( (_encryptedHeader == null) || (_encryptedHeader.length <= 0) ) if ( (_encryptedHeader == null) || (_encryptedHeader.length <= 0) )
throw new DataFormatException("No header to decrypt"); throw new DataFormatException("No header to decrypt");
byte decr[] = ElGamalAESEngine.decrypt(_encryptedHeader, key); byte decr[] = _context.elGamalAESEngine().decrypt(_encryptedHeader, key);
if (decr == null) if (decr == null)
throw new DataFormatException("Decrypted data is null"); throw new DataFormatException("Decrypted data is null");
@ -103,14 +107,16 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl {
} }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { 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 { try {
int headerSize = (int)DataHelper.readLong(in, 2); int headerSize = (int)DataHelper.readLong(in, 2);
_encryptedHeader = new byte[headerSize]; _encryptedHeader = new byte[headerSize];
int read = read(in, _encryptedHeader); int read = read(in, _encryptedHeader);
if (read != headerSize) if (read != headerSize)
throw new DataFormatException("Not enough bytes to read the header (read = " + read + ", required = " + headerSize + ")"); throw new DataFormatException("Not enough bytes to read the header (read = " + read
_message = new I2NPMessageHandler().readMessage(in); + ", required = " + headerSize + ")");
_message = _handler.readMessage(in);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Unable to load the message data", dfe); throw new I2NPMessageException("Unable to load the message data", dfe);
} }

View File

@ -18,6 +18,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.TunnelId; import net.i2p.data.TunnelId;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines the message sent to a router to request that it participate in a * Defines the message sent to a router to request that it participate in a
@ -52,7 +53,8 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
private final static long FLAG_DUMMY = 1 << 7; private final static long FLAG_DUMMY = 1 << 7;
private final static long FLAG_REORDER = 1 << 6; private final static long FLAG_REORDER = 1 << 6;
public TunnelCreateMessage() { public TunnelCreateMessage(I2PAppContext context) {
super(context);
setParticipantType(-1); setParticipantType(-1);
setNextRouter(null); setNextRouter(null);
setTunnelId(null); setTunnelId(null);
@ -176,53 +178,6 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
} catch (Throwable t) { } catch (Throwable t) {
throw new I2NPMessageException("Error writing out the message data", 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(); return os.toByteArray();
} }

View File

@ -17,6 +17,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.Hash;
import net.i2p.data.TunnelId; import net.i2p.data.TunnelId;
import net.i2p.util.Log; 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
@ -37,7 +38,8 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl {
public final static int STATUS_FAILED_CERTIFICATE = 3; public final static int STATUS_FAILED_CERTIFICATE = 3;
public final static int STATUS_FAILED_DELETED = 100; public final static int STATUS_FAILED_DELETED = 100;
public TunnelCreateStatusMessage() { public TunnelCreateStatusMessage(I2PAppContext context) {
super(context);
setTunnelId(null); setTunnelId(null);
setStatus(-1); setStatus(-1);
setFromHash(null); setFromHash(null);

View File

@ -16,6 +16,7 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.TunnelId; import net.i2p.data.TunnelId;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/** /**
* Defines the message sent between routers for tunnel delivery * Defines the message sent between routers for tunnel delivery
@ -34,7 +35,8 @@ public class TunnelMessage extends I2NPMessageImpl {
private final static int FLAG_INCLUDESTRUCTURE = 0; private final static int FLAG_INCLUDESTRUCTURE = 0;
private final static int FLAG_DONT_INCLUDESTRUCTURE = 1; private final static int FLAG_DONT_INCLUDESTRUCTURE = 1;
public TunnelMessage() { public TunnelMessage(I2PAppContext context) {
super(context);
setTunnelId(null); setTunnelId(null);
setData(null); setData(null);
setVerificationStructure(null); setVerificationStructure(null);

View File

@ -21,13 +21,13 @@ import net.i2p.data.Signature;
import net.i2p.data.SigningPrivateKey; import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey; import net.i2p.data.SigningPublicKey;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.router.RouterContext;
/** /**
* *
* @author jrandom * @author jrandom
*/ */
public class TunnelVerificationStructure extends DataStructureImpl { public class TunnelVerificationStructure extends DataStructureImpl {
private final static Log _log = new Log(TunnelVerificationStructure.class);
private Hash _msgHash; private Hash _msgHash;
private Signature _authSignature; private Signature _authSignature;
@ -42,15 +42,15 @@ public class TunnelVerificationStructure extends DataStructureImpl {
public Signature getAuthorizationSignature() { return _authSignature; } public Signature getAuthorizationSignature() { return _authSignature; }
public void setAuthorizationSignature(Signature sig) { _authSignature = sig; } public void setAuthorizationSignature(Signature sig) { _authSignature = sig; }
public void sign(SigningPrivateKey key) { public void sign(RouterContext context, SigningPrivateKey key) {
if (_msgHash != null) { if (_msgHash != null) {
Signature sig = DSAEngine.getInstance().sign(_msgHash.getData(), key); Signature sig = context.dsa().sign(_msgHash.getData(), key);
setAuthorizationSignature(sig); setAuthorizationSignature(sig);
} }
} }
public boolean verifySignature(SigningPublicKey key) { public boolean verifySignature(RouterContext context, SigningPublicKey key) {
if (_msgHash == null) return false; if (_msgHash == null) return false;
return DSAEngine.getInstance().verifySignature(_authSignature, _msgHash.getData(), key); return context.dsa().verifySignature(_authSignature, _msgHash.getData(), key);
} }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {

View File

@ -21,8 +21,6 @@ import net.i2p.router.client.ClientManagerFacadeImpl;
* @author jrandom * @author jrandom
*/ */
public abstract class ClientManagerFacade implements Service { 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 * 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 { class DummyClientManagerFacade extends ClientManagerFacade {
private RouterContext _context;
public DummyClientManagerFacade(RouterContext ctx) {
_context = ctx;
}
public boolean isLocal(Hash destHash) { return true; } public boolean isLocal(Hash destHash) { return true; }
public boolean isLocal(Destination dest) { return true; } public boolean isLocal(Destination dest) { return true; }
public void reportAbuse(Destination dest, String reason, int severity) { } public void reportAbuse(Destination dest, String reason, int severity) { }
public void messageReceived(ClientMessage msg) {} public void messageReceived(ClientMessage msg) {}
public void requestLeaseSet(Destination dest, LeaseSet set, long timeout, Job onCreateJob, Job onFailedJob) { public void requestLeaseSet(Destination dest, LeaseSet set, long timeout,
JobQueue.getInstance().addJob(onFailedJob); Job onCreateJob, Job onFailedJob) {
} _context.jobQueue().addJob(onFailedJob);
public void startup() {
//JobQueue.getInstance().addJob(new PollOutboundClientMessagesJob());
} }
public void startup() {}
public void stopAcceptingClients() { } public void stopAcceptingClients() { }
public void shutdown() {} public void shutdown() {}

View File

@ -25,15 +25,12 @@ import net.i2p.util.Log;
* *
*/ */
public class ClientMessagePool { public class ClientMessagePool {
private final static Log _log = new Log(ClientMessagePool.class); private Log _log;
private static ClientMessagePool _instance = new ClientMessagePool(); private RouterContext _context;
public static final ClientMessagePool getInstance() { return _instance; }
private List _inMessages;
private List _outMessages;
private ClientMessagePool() { public ClientMessagePool(RouterContext context) {
_inMessages = new ArrayList(); _context = context;
_outMessages = new ArrayList(); _log = _context.logManager().getLog(ClientMessagePool.class);
} }
/** /**
@ -42,84 +39,13 @@ public class ClientMessagePool {
* *
*/ */
public void add(ClientMessage msg) { public void add(ClientMessage msg) {
if ( (ClientManagerFacade.getInstance().isLocal(msg.getDestination())) || if ( (_context.clientManager().isLocal(msg.getDestination())) ||
(ClientManagerFacade.getInstance().isLocal(msg.getDestinationHash())) ) { (_context.clientManager().isLocal(msg.getDestinationHash())) ) {
_log.debug("Adding message for local delivery"); _log.debug("Adding message for local delivery");
ClientManagerFacade.getInstance().messageReceived(msg); _context.clientManager().messageReceived(msg);
//synchronized (_inMessages) {
// _inMessages.add(msg);
//}
} else { } else {
_log.debug("Adding message for remote delivery"); _log.debug("Adding message for remote delivery");
//JobQueue.getInstance().addJob(new ProcessOutboundClientMessageJob(msg)); _context.jobQueue().addJob(new OutboundClientMessageJob(_context, 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());
}
} }

View File

@ -11,20 +11,12 @@ package net.i2p.router;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import net.i2p.router.transport.CommSystemFacadeImpl;
/** /**
* Manages the communication subsystem between peers, including connections, * Manages the communication subsystem between peers, including connections,
* listeners, transports, connection keys, etc. * listeners, transports, connection keys, etc.
* *
*/ */
public abstract class CommSystemFacade implements Service { 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 abstract void processMessage(OutNetMessage msg);
public String renderStatusHTML() { return ""; } public String renderStatusHTML() { return ""; }

View File

@ -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) {}
}
}
}

View File

@ -26,17 +26,18 @@ import net.i2p.util.Log;
* *
*/ */
public class InNetMessagePool { public class InNetMessagePool {
private final static Log _log = new Log(InNetMessagePool.class); private Log _log;
private static InNetMessagePool _instance = new InNetMessagePool(); private RouterContext _context;
public final static InNetMessagePool getInstance() { return _instance; }
private List _messages; private List _messages;
private Map _handlerJobBuilders; private Map _handlerJobBuilders;
private InNetMessagePool() { public InNetMessagePool(RouterContext context) {
_context = context;
_messages = new ArrayList(); _messages = new ArrayList();
_handlerJobBuilders = new HashMap(); _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 }); _log = _context.logManager().getLog(InNetMessagePool.class);
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 }); _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) { public HandlerJobBuilder registerHandlerJobBuilder(int i2npMessageType, HandlerJobBuilder builder) {
@ -57,15 +58,15 @@ public class InNetMessagePool {
*/ */
public int add(InNetMessage msg) { public int add(InNetMessage msg) {
Date exp = msg.getMessage().getMessageExpiration(); 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 (!valid) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Duplicate message received [" + msg.getMessage().getUniqueId() _log.warn("Duplicate message received [" + msg.getMessage().getUniqueId()
+ " expiring on " + exp + "]: " + msg.getMessage().getClass().getName()); + " expiring on " + exp + "]: " + msg.getMessage().getClass().getName());
StatManager.getInstance().addRateData("inNetPool.dropped", 1, 0); _context.statManager().addRateData("inNetPool.dropped", 1, 0);
StatManager.getInstance().addRateData("inNetPool.duplicate", 1, 0); _context.statManager().addRateData("inNetPool.duplicate", 1, 0);
MessageHistory.getInstance().droppedOtherMessage(msg.getMessage()); _context.messageHistory().droppedOtherMessage(msg.getMessage());
MessageHistory.getInstance().messageProcessingError(msg.getMessage().getUniqueId(), _context.messageHistory().messageProcessingError(msg.getMessage().getUniqueId(),
msg.getMessage().getClass().getName(), msg.getMessage().getClass().getName(),
"Duplicate/expired"); "Duplicate/expired");
return -1; return -1;
@ -87,14 +88,14 @@ public class InNetMessagePool {
Job job = builder.createJob(msg.getMessage(), msg.getFromRouter(), Job job = builder.createJob(msg.getMessage(), msg.getFromRouter(),
msg.getFromRouterHash(), msg.getReplyBlock()); msg.getFromRouterHash(), msg.getReplyBlock());
if (job != null) { if (job != null) {
JobQueue.getInstance().addJob(job); _context.jobQueue().addJob(job);
synchronized (_messages) { synchronized (_messages) {
size = _messages.size(); size = _messages.size();
} }
} }
} }
List origMessages = OutboundMessageRegistry.getInstance().getOriginalMessages(msg.getMessage()); List origMessages = _context.messageRegistry().getOriginalMessages(msg.getMessage());
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Original messages for inbound message: " + origMessages.size()); _log.debug("Original messages for inbound message: " + origMessages.size());
if (origMessages.size() > 1) { if (origMessages.size() > 1) {
@ -112,7 +113,7 @@ public class InNetMessagePool {
if (job != null) { if (job != null) {
job.setMessage(msg.getMessage()); job.setMessage(msg.getMessage());
JobQueue.getInstance().addJob(job); _context.jobQueue().addJob(job);
} }
} }
@ -120,14 +121,14 @@ public class InNetMessagePool {
// not handled as a reply // not handled as a reply
if (size == -1) { if (size == -1) {
// was not handled via HandlerJobBuilder // was not handled via HandlerJobBuilder
MessageHistory.getInstance().droppedOtherMessage(msg.getMessage()); _context.messageHistory().droppedOtherMessage(msg.getMessage());
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("Message " + msg.getMessage() + " was not handled by a HandlerJobBuilder - DROPPING: " _log.error("Message " + msg.getMessage() + " was not handled by a HandlerJobBuilder - DROPPING: "
+ msg, new Exception("DROPPED MESSAGE")); + msg, new Exception("DROPPED MESSAGE"));
StatManager.getInstance().addRateData("inNetPool.dropped", 1, 0); _context.statManager().addRateData("inNetPool.dropped", 1, 0);
} else { } else {
String mtype = msg.getMessage().getClass().getName(); String mtype = msg.getMessage().getClass().getName();
MessageHistory.getInstance().receiveMessage(mtype, msg.getMessage().getUniqueId(), _context.messageHistory().receiveMessage(mtype, msg.getMessage().getUniqueId(),
msg.getMessage().getMessageExpiration(), msg.getMessage().getMessageExpiration(),
msg.getFromRouterHash(), true); msg.getFromRouterHash(), true);
return size; return size;
@ -135,7 +136,7 @@ public class InNetMessagePool {
} }
String mtype = msg.getMessage().getClass().getName(); String mtype = msg.getMessage().getClass().getName();
MessageHistory.getInstance().receiveMessage(mtype, msg.getMessage().getUniqueId(), _context.messageHistory().receiveMessage(mtype, msg.getMessage().getUniqueId(),
msg.getMessage().getMessageExpiration(), msg.getMessage().getMessageExpiration(),
msg.getFromRouterHash(), true); msg.getFromRouterHash(), true);
return size; return size;
@ -174,19 +175,4 @@ public class InNetMessagePool {
return _messages.size(); 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());
}
} }

View File

@ -13,14 +13,16 @@ import net.i2p.util.Clock;
* Base implementation of a Job * Base implementation of a Job
*/ */
public abstract class JobImpl implements Job { public abstract class JobImpl implements Job {
protected RouterContext _context;
private JobTiming _timing; private JobTiming _timing;
private static int _idSrc = 0; private static int _idSrc = 0;
private int _id; private int _id;
private Exception _addedBy; private Exception _addedBy;
private long _madeReadyOn; private long _madeReadyOn;
public JobImpl() { public JobImpl(RouterContext context) {
_timing = new JobTiming(); _context = context;
_timing = new JobTiming(context);
_id = ++_idSrc; _id = ++_idSrc;
_addedBy = null; _addedBy = null;
_madeReadyOn = 0; _madeReadyOn = 0;
@ -42,11 +44,11 @@ public abstract class JobImpl implements Job {
public Exception getAddedBy() { return _addedBy; } public Exception getAddedBy() { return _addedBy; }
public long getMadeReadyOn() { return _madeReadyOn; } public long getMadeReadyOn() { return _madeReadyOn; }
public void madeReady() { _madeReadyOn = Clock.getInstance().now(); } public void madeReady() { _madeReadyOn = _context.clock().now(); }
public void dropped() {} public void dropped() {}
protected void requeue(long delayMs) { protected void requeue(long delayMs) {
getTiming().setStartAfter(Clock.getInstance().now() + delayMs); getTiming().setStartAfter(_context.clock().now() + delayMs);
JobQueue.getInstance().addJob(this); _context.jobQueue().addJob(this);
} }
} }

View File

@ -11,7 +11,7 @@ package net.i2p.router;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList; import java.util.ArrayList;
import java.util.TreeMap; import java.util.TreeMap;
import net.i2p.router.message.HandleSourceRouteReplyMessageJob; import net.i2p.router.message.HandleSourceRouteReplyMessageJob;
@ -29,22 +29,21 @@ import net.i2p.util.Log;
* *
*/ */
public class JobQueue { public class JobQueue {
private final static Log _log = new Log(JobQueue.class); private Log _log;
private static JobQueue _instance = new JobQueue(); private RouterContext _context;
public static JobQueue getInstance() { return _instance; }
/** Integer (runnerId) to JobQueueRunner for created runners */ /** Integer (runnerId) to JobQueueRunner for created runners */
private static HashMap _queueRunners; private HashMap _queueRunners;
/** a counter to identify a job runner */ /** a counter to identify a job runner */
private volatile static int _runnerId = 0; private volatile static int _runnerId = 0;
/** list of jobs that are ready to run ASAP */ /** 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 */ /** 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 */ /** when true, don't run any new jobs or update any limits, etc */
private boolean _paused; private boolean _paused;
/** job name to JobStat for that job */ /** job name to JobStat for that job */
private static TreeMap _jobStats; private TreeMap _jobStats;
/** how many job queue runners can go concurrently */ /** how many job queue runners can go concurrently */
private int _maxRunners; private int _maxRunners;
private QueuePumper _pumper; private QueuePumper _pumper;
@ -92,8 +91,6 @@ public class JobQueue {
private final static String PROP_MAX_WAITING_JOBS = "router.maxWaitingJobs"; private final static String PROP_MAX_WAITING_JOBS = "router.maxWaitingJobs";
static { 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,10 +99,21 @@ public class JobQueue {
*/ */
private Object _runnerLock = new Object(); private Object _runnerLock = new Object();
private JobQueue() { 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; _alive = true;
_readyJobs = new LinkedList(); _readyJobs = new ArrayList();
_timedJobs = new LinkedList(); _timedJobs = new ArrayList();
_queueRunners = new HashMap(); _queueRunners = new HashMap();
_paused = false; _paused = false;
_jobStats = new TreeMap(); _jobStats = new TreeMap();
@ -143,20 +151,21 @@ public class JobQueue {
} }
} }
StatManager.getInstance().addRateData("jobQueue.readyJobs", numReady, 0); _context.statManager().addRateData("jobQueue.readyJobs", numReady, 0);
if (shouldDrop(job, numReady)) { if (shouldDrop(job, numReady)) {
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("Dropping job due to overload! # ready jobs: " + numReady + ": job = " + job); _log.error("Dropping job due to overload! # ready jobs: "
+ numReady + ": job = " + job);
job.dropped(); job.dropped();
StatManager.getInstance().addRateData("jobQueue.droppedJobs", 1, 1); _context.statManager().addRateData("jobQueue.droppedJobs", 1, 1);
awaken(1); awaken(1);
return; return;
} }
if (!alreadyExists) { if (!alreadyExists) {
if (job.getTiming().getStartAfter() <= Clock.getInstance().now()) { if (job.getTiming().getStartAfter() <= _context.clock().now()) {
// don't skew us - its 'start after' its been queued, or later // don't skew us - its 'start after' its been queued, or later
job.getTiming().setStartAfter(Clock.getInstance().now()); job.getTiming().setStartAfter(_context.clock().now());
if (job instanceof JobImpl) if (job instanceof JobImpl)
((JobImpl)job).madeReady(); ((JobImpl)job).madeReady();
synchronized (_readyJobs) { synchronized (_readyJobs) {
@ -248,6 +257,7 @@ public class JobQueue {
_log.debug("Using a ready job after waking up " + (ready-1) + " others"); _log.debug("Using a ready job after waking up " + (ready-1) + " others");
return rv; return rv;
} }
try { try {
synchronized (_runnerLock) { synchronized (_runnerLock) {
_runnerLock.wait(1000); _runnerLock.wait(1000);
@ -264,8 +274,8 @@ public class JobQueue {
*/ */
private int checkJobTimings() { private int checkJobTimings() {
boolean newJobsReady = false; boolean newJobsReady = false;
long now = Clock.getInstance().now(); long now = _context.clock().now();
LinkedList toAdd = new LinkedList(); ArrayList toAdd = new ArrayList(4);
synchronized (_timedJobs) { synchronized (_timedJobs) {
for (int i = 0; i < _timedJobs.size(); i++) { for (int i = 0; i < _timedJobs.size(); i++) {
Job j = (Job)_timedJobs.get(i); Job j = (Job)_timedJobs.get(i);
@ -308,9 +318,10 @@ public class JobQueue {
// specified // specified
if (_queueRunners.size() < numThreads) { if (_queueRunners.size() < numThreads) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Increasing the number of queue runners from " + _queueRunners.size() + " to " + numThreads); _log.info("Increasing the number of queue runners from "
+ _queueRunners.size() + " to " + numThreads);
for (int i = _queueRunners.size(); i < numThreads; i++) { for (int i = _queueRunners.size(); i < numThreads; i++) {
JobQueueRunner runner = new JobQueueRunner(i); JobQueueRunner runner = new JobQueueRunner(_context, i);
_queueRunners.put(new Integer(i), runner); _queueRunners.put(new Integer(i), runner);
Thread t = new I2PThread(runner); Thread t = new I2PThread(runner);
t.setName("JobQueue"+(_runnerId++)); t.setName("JobQueue"+(_runnerId++));
@ -374,7 +385,7 @@ public class JobQueue {
private long _lastLimitUpdated; private long _lastLimitUpdated;
public QueuePumper() { public QueuePumper() {
_lastLimitUpdated = 0; _lastLimitUpdated = 0;
Clock.getInstance().addUpdateListener(this); _context.clock().addUpdateListener(this);
} }
public void run() { public void run() {
try { try {
@ -384,7 +395,7 @@ public class JobQueue {
} }
// periodically update our max runners limit // periodically update our max runners limit
long now = Clock.getInstance().now(); long now = _context.clock().now();
if (now > _lastLimitUpdated + MAX_LIMIT_UPDATE_DELAY) { if (now > _lastLimitUpdated + MAX_LIMIT_UPDATE_DELAY) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Updating the limits"); _log.info("Updating the limits");
@ -401,7 +412,7 @@ public class JobQueue {
try { Thread.sleep(500); } catch (InterruptedException ie) {} try { Thread.sleep(500); } catch (InterruptedException ie) {}
} }
} catch (Throwable t) { } catch (Throwable t) {
Clock.getInstance().removeUpdateListener(this); _context.clock().removeUpdateListener(this);
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("wtf, pumper killed", t); _log.error("wtf, pumper killed", t);
} }
@ -422,8 +433,8 @@ public class JobQueue {
void updateStats(Job job, long doStart, long origStartAfter, long duration) { void updateStats(Job job, long doStart, long origStartAfter, long duration) {
String key = job.getName(); String key = job.getName();
long lag = doStart - origStartAfter; // how long were we ready and waiting? long lag = doStart - origStartAfter; // how long were we ready and waiting?
MessageHistory hist = MessageHistory.getInstance(); MessageHistory hist = _context.messageHistory();
long uptime = Router.getInstance().getUptime(); long uptime = _context.router().getUptime();
synchronized (_jobStats) { synchronized (_jobStats) {
if (!_jobStats.containsKey(key)) if (!_jobStats.containsKey(key))
@ -434,14 +445,11 @@ public class JobQueue {
} }
String dieMsg = null; String dieMsg = null;
boolean dumpRunners = false;
if (lag > _lagWarning) { if (lag > _lagWarning) {
dieMsg = "Lag too long for job " + job.getName() + " [" + lag + "ms and a run time of " + duration + "ms]"; dieMsg = "Lag too long for job " + job.getName() + " [" + lag + "ms and a run time of " + duration + "ms]";
dumpRunners = true;
} else if (duration > _runWarning) { } else if (duration > _runWarning) {
dieMsg = "Job run too long for job " + job.getName() + " [" + lag + "ms lag and run time of " + duration + "ms]"; dieMsg = "Job run too long for job " + job.getName() + " [" + lag + "ms lag and run time of " + duration + "ms]";
dumpRunners = true;
} }
if (dieMsg != null) { if (dieMsg != null) {
@ -451,9 +459,6 @@ public class JobQueue {
hist.messageProcessingError(-1, JobQueue.class.getName(), dieMsg); hist.messageProcessingError(-1, JobQueue.class.getName(), dieMsg);
} }
if (dumpRunners)
dumpRunners(true);
if ( (lag > _lagFatal) && (uptime > _warmupTime) ) { if ( (lag > _lagFatal) && (uptime > _warmupTime) ) {
// this is fscking bad - the network at this size shouldn't have this much real contention // this is fscking bad - the network at this size shouldn't have this much real contention
// so we're going to DIE DIE DIE // so we're going to DIE DIE DIE
@ -463,6 +468,7 @@ public class JobQueue {
//Router.getInstance().shutdown(); //Router.getInstance().shutdown();
return; return;
} }
if ( (uptime > _warmupTime) && (duration > _runFatal) ) { if ( (uptime > _warmupTime) && (duration > _runFatal) ) {
// slow CPUs can get hosed with ElGamal, but 10s is too much. // slow CPUs can get hosed with ElGamal, but 10s is too much.
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
@ -482,7 +488,7 @@ public class JobQueue {
* *
*/ */
private void updateMaxLimit() { private void updateMaxLimit() {
String str = Router.getInstance().getConfigSetting(PROP_MAX_RUNNERS); String str = _context.router().getConfigSetting(PROP_MAX_RUNNERS);
if (str != null) { if (str != null) {
try { try {
_maxRunners = Integer.parseInt(str); _maxRunners = Integer.parseInt(str);
@ -502,7 +508,7 @@ public class JobQueue {
* *
*/ */
private void updateTimingLimits() { private void updateTimingLimits() {
String str = Router.getInstance().getConfigSetting(PROP_LAG_WARNING); String str = _context.router().getConfigSetting(PROP_LAG_WARNING);
if (str != null) { if (str != null) {
try { try {
_lagWarning = Integer.parseInt(str); _lagWarning = Integer.parseInt(str);
@ -516,7 +522,7 @@ public class JobQueue {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Setting the warning job lag time to " + _lagWarning + "ms"); _log.info("Setting the warning job lag time to " + _lagWarning + "ms");
str = Router.getInstance().getConfigSetting(PROP_LAG_FATAL); str = _context.router().getConfigSetting(PROP_LAG_FATAL);
if (str != null) { if (str != null) {
try { try {
_lagFatal = Integer.parseInt(str); _lagFatal = Integer.parseInt(str);
@ -530,7 +536,7 @@ public class JobQueue {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Setting the fatal job lag time to " + _lagFatal + "ms"); _log.info("Setting the fatal job lag time to " + _lagFatal + "ms");
str = Router.getInstance().getConfigSetting(PROP_RUN_WARNING); str = _context.router().getConfigSetting(PROP_RUN_WARNING);
if (str != null) { if (str != null) {
try { try {
_runWarning = Integer.parseInt(str); _runWarning = Integer.parseInt(str);
@ -544,7 +550,7 @@ public class JobQueue {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Setting the warning job run time to " + _runWarning + "ms"); _log.info("Setting the warning job run time to " + _runWarning + "ms");
str = Router.getInstance().getConfigSetting(PROP_RUN_FATAL); str = _context.router().getConfigSetting(PROP_RUN_FATAL);
if (str != null) { if (str != null) {
try { try {
_runFatal = Integer.parseInt(str); _runFatal = Integer.parseInt(str);
@ -558,7 +564,7 @@ public class JobQueue {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Setting the fatal job run time to " + _runFatal + "ms"); _log.info("Setting the fatal job run time to " + _runFatal + "ms");
str = Router.getInstance().getConfigSetting(PROP_WARMUM_TIME); str = _context.router().getConfigSetting(PROP_WARMUM_TIME);
if (str != null) { if (str != null) {
try { try {
_warmupTime = Integer.parseInt(str); _warmupTime = Integer.parseInt(str);
@ -570,7 +576,7 @@ public class JobQueue {
_warmupTime = DEFAULT_WARMUP_TIME; _warmupTime = DEFAULT_WARMUP_TIME;
} }
str = Router.getInstance().getConfigSetting(PROP_MAX_WAITING_JOBS); str = _context.router().getConfigSetting(PROP_MAX_WAITING_JOBS);
if (str != null) { if (str != null) {
try { try {
_maxWaitingJobs = Integer.parseInt(str); _maxWaitingJobs = Integer.parseInt(str);
@ -590,11 +596,11 @@ public class JobQueue {
//// ////
public String renderStatusHTML() { public String renderStatusHTML() {
LinkedList readyJobs = new LinkedList(); ArrayList readyJobs = null;
LinkedList timedJobs = new LinkedList(); ArrayList timedJobs = null;
LinkedList activeJobs = new LinkedList(); ArrayList activeJobs = new ArrayList(4);
synchronized (_readyJobs) { readyJobs.addAll(_readyJobs); } synchronized (_readyJobs) { readyJobs = new ArrayList(_readyJobs); }
synchronized (_timedJobs) { timedJobs.addAll(_timedJobs); } synchronized (_timedJobs) { timedJobs = new ArrayList(_timedJobs); }
synchronized (_queueRunners) { synchronized (_queueRunners) {
for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext();) { for (Iterator iter = _queueRunners.values().iterator(); iter.hasNext();) {
JobQueueRunner runner = (JobQueueRunner)iter.next(); JobQueueRunner runner = (JobQueueRunner)iter.next();
@ -603,7 +609,7 @@ public class JobQueue {
activeJobs.add(job.getName()); activeJobs.add(job.getName());
} }
} }
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer(20*1024);
buf.append("<h2>JobQueue</h2>"); buf.append("<h2>JobQueue</h2>");
buf.append("# runners: "); buf.append("# runners: ");
synchronized (_queueRunners) { synchronized (_queueRunners) {
@ -629,7 +635,8 @@ public class JobQueue {
} }
for (Iterator iter = ordered.values().iterator(); iter.hasNext(); ) { for (Iterator iter = ordered.values().iterator(); iter.hasNext(); ) {
Job j = (Job)iter.next(); Job j = (Job)iter.next();
buf.append("<li>").append(j.getName()).append(" @ ").append(new Date(j.getTiming().getStartAfter())).append("</li>\n"); buf.append("<li>").append(j.getName()).append(" @ ");
buf.append(new Date(j.getTiming().getStartAfter())).append("</li>\n");
} }
buf.append("</ol>\n"); buf.append("</ol>\n");
buf.append(getJobStats()); buf.append(getJobStats());
@ -638,7 +645,7 @@ public class JobQueue {
/** render the HTML for the job stats */ /** render the HTML for the job stats */
private String getJobStats() { private String getJobStats() {
StringBuffer buf = new StringBuffer(1024); StringBuffer buf = new StringBuffer(16*1024);
buf.append("<table border=\"1\">\n"); buf.append("<table border=\"1\">\n");
buf.append("<tr><td><b>Job</b></td><td><b>Runs</b></td>"); buf.append("<tr><td><b>Job</b></td><td><b>Runs</b></td>");
buf.append("<td><b>Time</b></td><td><b><i>Avg</i></b></td><td><b><i>Max</i></b></td><td><b><i>Min</i></b></td>"); buf.append("<td><b>Time</b></td><td><b><i>Avg</i></b></td><td><b><i>Max</i></b></td><td><b><i>Min</i></b></td>");
@ -709,40 +716,4 @@ public class JobQueue {
buf.append("</table>\n"); buf.append("</table>\n");
return buf.toString(); 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());
}
} }

View File

@ -6,73 +6,75 @@ import net.i2p.util.Log;
/** a do run run run a do run run */ /** a do run run run a do run run */
class JobQueueRunner implements Runnable { class JobQueueRunner implements Runnable {
private final static Log _log = new Log(JobQueueRunner.class); private Log _log;
private RouterContext _context;
private boolean _keepRunning; private boolean _keepRunning;
private int _id; private int _id;
private long _numJobs; private long _numJobs;
private Job _currentJob; private Job _currentJob;
static { public JobQueueRunner(RouterContext context, int id) {
StatManager.getInstance().createRateStat("jobQueue.jobRun", "How long jobs take", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); _context = context;
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(int id) {
_id = id; _id = id;
_keepRunning = true; _keepRunning = true;
_numJobs = 0; _numJobs = 0;
_currentJob = null; _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 Job getCurrentJob() { return _currentJob; } public Job getCurrentJob() { return _currentJob; }
public int getRunnerId() { return _id; } public int getRunnerId() { return _id; }
public void stopRunning() { _keepRunning = false; } public void stopRunning() { _keepRunning = false; }
public void run() { public void run() {
long lastActive = Clock.getInstance().now();; long lastActive = _context.clock().now();
while ( (_keepRunning) && (JobQueue.getInstance().isAlive()) ) { while ( (_keepRunning) && (_context.jobQueue().isAlive()) ) {
try { try {
Job job = JobQueue.getInstance().getNext(); Job job = _context.jobQueue().getNext();
if (job == null) continue; if (job == null) continue;
long now = Clock.getInstance().now(); long now = _context.clock().now();
long enqueuedTime = 0; long enqueuedTime = 0;
if (job instanceof JobImpl) { if (job instanceof JobImpl) {
long when = ((JobImpl)job).getMadeReadyOn(); long when = ((JobImpl)job).getMadeReadyOn();
if (when <= 0) { if (when <= 0) {
_log.error("Job was not made ready?! " + job, new Exception("Not made ready?!")); _log.error("Job was not made ready?! " + job,
new Exception("Not made ready?!"));
} else { } else {
enqueuedTime = now - when; enqueuedTime = now - when;
} }
} }
long betweenJobs = now - lastActive; long betweenJobs = now - lastActive;
StatManager.getInstance().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs); _context.statManager().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs);
_currentJob = job; _currentJob = job;
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName()); _log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName());
long origStartAfter = job.getTiming().getStartAfter(); long origStartAfter = job.getTiming().getStartAfter();
long doStart = Clock.getInstance().now(); long doStart = _context.clock().now();
job.getTiming().start(); job.getTiming().start();
runCurrentJob(); runCurrentJob();
job.getTiming().end(); job.getTiming().end();
long duration = job.getTiming().getActualEnd() - job.getTiming().getActualStart(); 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;
long beforeUpdate = Clock.getInstance().now(); _context.statManager().addRateData("jobQueue.jobRun", duration, duration);
JobQueue.getInstance().updateStats(job, doStart, origStartAfter, duration); _context.statManager().addRateData("jobQueue.jobLag", doStart - origStartAfter, 0);
long diff = Clock.getInstance().now() - beforeUpdate; _context.statManager().addRateData("jobQueue.jobWait", enqueuedTime, enqueuedTime);
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 (diff > 100) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Updating statistics for the job took too long [" + diff + "ms]"); _log.warn("Updating statistics for the job took too long [" + diff + "ms]");
} }
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Job duration " + duration + "ms for " + job.getName() + " with lag of " + (doStart-origStartAfter) + "ms"); _log.debug("Job duration " + duration + "ms for " + job.getName()
lastActive = Clock.getInstance().now(); + " with lag of " + (doStart-origStartAfter) + "ms");
lastActive = _context.clock().now();
_currentJob = null; _currentJob = null;
} catch (Throwable t) { } catch (Throwable t) {
if (_log.shouldLog(Log.CRIT)) if (_log.shouldLog(Log.CRIT))
@ -81,7 +83,7 @@ class JobQueueRunner implements Runnable {
} }
if (_log.shouldLog(Log.CRIT)) if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "Queue runner " + _id + " exiting"); _log.log(Log.CRIT, "Queue runner " + _id + " exiting");
JobQueue.getInstance().removeRunner(_id); _context.jobQueue().removeRunner(_id);
} }
private void runCurrentJob() { private void runCurrentJob() {
@ -91,7 +93,7 @@ class JobQueueRunner implements Runnable {
try { try {
if (_log.shouldLog(Log.CRIT)) if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "Router ran out of memory, shutting down", oom); _log.log(Log.CRIT, "Router ran out of memory, shutting down", oom);
Router.getInstance().shutdown(); _context.router().shutdown();
} catch (Throwable t) { } catch (Throwable t) {
System.err.println("***Router ran out of memory, shutting down hard"); System.err.println("***Router ran out of memory, shutting down hard");
} }
@ -99,10 +101,10 @@ class JobQueueRunner implements Runnable {
System.exit(-1); System.exit(-1);
} catch (Throwable t) { } catch (Throwable t) {
if (_log.shouldLog(Log.CRIT)) if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "Error processing job [" + _currentJob.getName() + "] on thread " + _id + ": " + t.getMessage(), t); _log.log(Log.CRIT, "Error processing job [" + _currentJob.getName()
+ "] on thread " + _id + ": " + t.getMessage(), t);
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error("The above job was enqueued by: ", _currentJob.getAddedBy()); _log.error("The above job was enqueued by: ", _currentJob.getAddedBy());
JobQueue.getInstance().dumpRunners(true);
} }
} }
} }

View File

@ -9,6 +9,7 @@ package net.i2p.router;
*/ */
import net.i2p.util.Clock; import net.i2p.util.Clock;
/** /**
* Define the timing requirements and statistics for a particular job * 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 _start;
private long _actualStart; private long _actualStart;
private long _actualEnd; private long _actualEnd;
private RouterContext _context;
public JobTiming() { public JobTiming(RouterContext context) {
_start = Clock.getInstance().now(); _context = context;
_start = context.clock().now();
_actualStart = 0; _actualStart = 0;
_actualEnd = 0; _actualEnd = 0;
Clock.getInstance().addUpdateListener(this); context.clock().addUpdateListener(this);
} }
/** /**
@ -42,7 +45,7 @@ public class JobTiming implements Clock.ClockUpdateListener {
* Notify the timing that the job began * 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 * # of milliseconds after the epoch the job actually ended
* *
@ -54,8 +57,8 @@ public class JobTiming implements Clock.ClockUpdateListener {
* *
*/ */
public void end() { public void end() {
_actualEnd = Clock.getInstance().now(); _actualEnd = _context.clock().now();
Clock.getInstance().removeUpdateListener(this); _context.clock().removeUpdateListener(this);
} }
public void offsetChanged(long delta) { public void offsetChanged(long delta) {

View File

@ -32,9 +32,8 @@ import net.i2p.util.Log;
* *
*/ */
public class KeyManager { public class KeyManager {
private final static Log _log = new Log(KeyManager.class); private Log _log;
private static KeyManager _instance = new KeyManager(); private RouterContext _context;
public static KeyManager getInstance() { return _instance; }
private PrivateKey _privateKey; private PrivateKey _privateKey;
private PublicKey _publicKey; private PublicKey _publicKey;
private SigningPrivateKey _signingPrivateKey; private SigningPrivateKey _signingPrivateKey;
@ -49,13 +48,15 @@ public class KeyManager {
private final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key"; private final static String KEYFILE_PUBLIC_SIGNING = "publicSigning.key";
private final static long DELAY = 30*1000; private final static long DELAY = 30*1000;
private KeyManager() { public KeyManager(RouterContext context) {
_context = context;
_log = _context.logManager().getLog(KeyManager.class);
setPrivateKey(null); setPrivateKey(null);
setPublicKey(null); setPublicKey(null);
setSigningPrivateKey(null); setSigningPrivateKey(null);
setSigningPublicKey(null); setSigningPublicKey(null);
_leaseSetKeys = new HashMap(); _leaseSetKeys = new HashMap();
JobQueue.getInstance().addJob(new SynchronizeKeysJob()); _context.jobQueue().addJob(new SynchronizeKeysJob());
} }
/** Configure the router's private key */ /** Configure the router's private key */
@ -101,8 +102,11 @@ public class KeyManager {
} }
private class SynchronizeKeysJob extends JobImpl { private class SynchronizeKeysJob extends JobImpl {
public SynchronizeKeysJob() {
super(KeyManager.this._context);
}
public void runJob() { public void runJob() {
String keyDir = Router.getInstance().getConfigSetting(PROP_KEYDIR); String keyDir = KeyManager.this._context.router().getConfigSetting(PROP_KEYDIR);
if (keyDir == null) if (keyDir == null)
keyDir = DEFAULT_KEYDIR; keyDir = DEFAULT_KEYDIR;
File dir = new File(keyDir); File dir = new File(keyDir);
@ -111,8 +115,8 @@ public class KeyManager {
if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite())
syncKeys(dir); syncKeys(dir);
getTiming().setStartAfter(Clock.getInstance().now()+DELAY); getTiming().setStartAfter(KeyManager.this._context.clock().now()+DELAY);
JobQueue.getInstance().addJob(this); KeyManager.this._context.jobQueue().addJob(this);
} }
private void syncKeys(File keyDir) { private void syncKeys(File keyDir) {

View File

@ -23,13 +23,16 @@ import net.i2p.util.Log;
* *
*/ */
public class MessageHistory { public class MessageHistory {
private final static Log _log = new Log(MessageHistory.class); private Log _log;
private static MessageHistory _instance; private RouterContext _context;
private List _unwrittenEntries; // list of raw entries (strings) yet to be written private List _unwrittenEntries; // list of raw entries (strings) yet to be written
private String _historyFile; // where to write private String _historyFile; // where to write
private String _localIdent; // placed in each entry to uniquely identify the local router private String _localIdent; // placed in each entry to uniquely identify the local router
private boolean _doLog; // true == we want to log private boolean _doLog; // true == we want to log
private boolean _doPause; // true == briefly stop writing data to the log (used while submitting it) 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 byte[] NL = System.getProperty("line.separator").getBytes();
private final static int FLUSH_SIZE = 1000; // write out at least once every 1000 entries 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 PROP_MESSAGE_HISTORY_FILENAME = "router.historyFilename";
public final static String DEFAULT_MESSAGE_HISTORY_FILENAME = "messageHistory.txt"; public final static String DEFAULT_MESSAGE_HISTORY_FILENAME = "messageHistory.txt";
public final static MessageHistory getInstance() { public MessageHistory(RouterContext context) {
if (_instance == null) _context = context;
initialize(); _reinitializeJob = new ReinitializeJob();
return _instance; _writeJob = new WriteJob();
} _submitMessageHistoryJob = new SubmitMessageHistoryJob(_context);
private final static void setInstance(MessageHistory hist) { initialize(true);
if (_instance != null) {
synchronized (_instance._unwrittenEntries) {
for (Iterator iter = _instance._unwrittenEntries.iterator(); iter.hasNext(); ) {
hist.addEntry((String)iter.next());
}
_instance._unwrittenEntries.clear();
}
}
_instance = hist;
} }
void setDoLog(boolean log) { _doLog = log; } void setDoLog(boolean log) { _doLog = log; }
@ -65,7 +59,7 @@ public class MessageHistory {
String getFilename() { return _historyFile; } String getFilename() { return _historyFile; }
private void updateSettings() { private void updateSettings() {
String keepHistory = Router.getInstance().getConfigSetting(PROP_KEEP_MESSAGE_HISTORY); String keepHistory = _context.router().getConfigSetting(PROP_KEEP_MESSAGE_HISTORY);
if (keepHistory != null) { if (keepHistory != null) {
_doLog = Boolean.TRUE.toString().equalsIgnoreCase(keepHistory); _doLog = Boolean.TRUE.toString().equalsIgnoreCase(keepHistory);
} else { } else {
@ -74,7 +68,7 @@ public class MessageHistory {
String filename = null; String filename = null;
if (_doLog) { if (_doLog) {
filename = Router.getInstance().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME); filename = _context.router().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME);
if ( (filename == null) || (filename.trim().length() <= 0) ) if ( (filename == null) || (filename.trim().length() <= 0) )
filename = DEFAULT_MESSAGE_HISTORY_FILENAME; filename = DEFAULT_MESSAGE_HISTORY_FILENAME;
} }
@ -85,55 +79,38 @@ public class MessageHistory {
* Call this whenever the router identity changes. * Call this whenever the router identity changes.
* *
*/ */
public static void initialize() { public void initialize(boolean forceReinitialize) {
initialize(false); if (!forceReinitialize) return;
}
public static void initialize(boolean forceReinitialize) {
if ( (!forceReinitialize) && (_instance != null) ) return;
if (Router.getInstance().getRouterInfo() == null) { if (_context.router().getRouterInfo() == null) {
ReinitializeJob j = ReinitializeJob.getInstance(); _reinitializeJob.getTiming().setStartAfter(_context.clock().now()+5000);
j.getTiming().setStartAfter(Clock.getInstance().now()+5000); _context.jobQueue().addJob(_reinitializeJob);
JobQueue.getInstance().addJob(j);
} else { } else {
String filename = null; String filename = null;
filename = Router.getInstance().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME); filename = _context.router().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME);
if ( (filename == null) || (filename.trim().length() <= 0) ) if ( (filename == null) || (filename.trim().length() <= 0) )
filename = DEFAULT_MESSAGE_HISTORY_FILENAME; 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; _doLog = DEFAULT_KEEP_MESSAGE_HISTORY;
_historyFile = filename; _historyFile = filename;
_localIdent = getName(localIdent); _localIdent = getName(_context.routerHash());
_unwrittenEntries = new LinkedList(); _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);
}
}
private final class ReinitializeJob extends JobImpl {
private ReinitializeJob() {
super(MessageHistory.this._context);
}
public void runJob() {
initialize(true);
}
public String getName() { return "Reinitialize message history"; }
} }
/** /**
@ -458,7 +435,7 @@ public class MessageHistory {
private final String getPrefix() { private final String getPrefix() {
StringBuffer buf = new StringBuffer(48); StringBuffer buf = new StringBuffer(48);
buf.append(getTime(new Date(Clock.getInstance().now()))); buf.append(getTime(new Date(_context.clock().now())));
buf.append(' ').append(_localIdent).append(": "); buf.append(' ').append(_localIdent).append(": ");
return buf.toString(); return buf.toString();
} }
@ -525,22 +502,27 @@ public class MessageHistory {
/** write out the message history once per minute, if not sooner */ /** write out the message history once per minute, if not sooner */
private final static long WRITE_DELAY = 60*1000; private final static long WRITE_DELAY = 60*1000;
private static class WriteJob extends JobImpl { private class WriteJob extends JobImpl {
public WriteJob() {
super(MessageHistory.this._context);
}
public String getName() { return "Write History Entries"; } public String getName() { return "Write History Entries"; }
public void runJob() { public void runJob() {
MessageHistory.getInstance().flushEntries(); flushEntries();
MessageHistory.getInstance().updateSettings(); updateSettings();
requeue(WRITE_DELAY); requeue(WRITE_DELAY);
} }
} }
public static void main(String args[]) { public static void main(String args[]) {
MessageHistory hist = new MessageHistory(new Hash(new byte[32]), "messageHistory.txt"); RouterContext ctx = new RouterContext(null);
MessageHistory.getInstance().setDoLog(false); MessageHistory hist = new MessageHistory(ctx);
//, new Hash(new byte[32]), "messageHistory.txt");
hist.setDoLog(false);
hist.addEntry("you smell before"); hist.addEntry("you smell before");
hist.getInstance().setDoLog(true); hist.setDoLog(true);
hist.addEntry("you smell after"); hist.addEntry("you smell after");
hist.getInstance().setDoLog(false); hist.setDoLog(false);
hist.addEntry("you smell finished"); hist.addEntry("you smell finished");
hist.flushEntries(); hist.flushEntries();
} }

View File

@ -17,21 +17,29 @@ import net.i2p.util.Log;
* *
*/ */
public class MessageValidator { public class MessageValidator {
private final static Log _log = new Log(MessageValidator.class); private Log _log;
private final static MessageValidator _instance = new MessageValidator(); private RouterContext _context;
public final static MessageValidator getInstance() { return _instance; }
/** /**
* Expiration date (as a Long) to message id (as a Long). * Expiration date (as a Long) to message id (as a Long).
* The expiration date (key) must be unique, so on collision, increment the value. * 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 ;) * 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) */ /** Message id (as a Long) */
private Set _receivedIds = new HashSet(1024); private Set _receivedIds;
/** synchronize on this before adjusting the received id data */ /** 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) * Determine if this message should be accepted as valid (not expired, not a duplicate)
@ -39,7 +47,7 @@ public class MessageValidator {
* @return true if the message should be accepted as valid, false otherwise * @return true if the message should be accepted as valid, false otherwise
*/ */
public boolean validateMessage(long messageId, long expiration) { public boolean validateMessage(long messageId, long expiration) {
long now = Clock.getInstance().now(); long now = _context.clock().now();
if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) { if (now - Router.CLOCK_FUDGE_FACTOR >= expiration) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Rejecting message " + messageId + " because it expired " + (now-expiration) + "ms ago"); _log.warn("Rejecting message " + messageId + " because it expired " + (now-expiration) + "ms ago");
@ -69,7 +77,7 @@ public class MessageValidator {
private boolean noteReception(long messageId, long messageExpiration) { private boolean noteReception(long messageId, long messageExpiration) {
Long id = new Long(messageId); Long id = new Long(messageId);
synchronized (_receivedIdLock) { synchronized (_receivedIdLock) {
locked_cleanReceivedIds(Clock.getInstance().now() - Router.CLOCK_FUDGE_FACTOR); locked_cleanReceivedIds(_context.clock().now() - Router.CLOCK_FUDGE_FACTOR);
if (_receivedIds.contains(id)) { if (_receivedIds.contains(id)) {
return true; return true;
} else { } else {
@ -89,7 +97,7 @@ public class MessageValidator {
* *
*/ */
private void cleanReceivedIds() { private void cleanReceivedIds() {
long now = Clock.getInstance().now() - Router.CLOCK_FUDGE_FACTOR ; long now = _context.clock().now() - Router.CLOCK_FUDGE_FACTOR ;
synchronized (_receivedIdLock) { synchronized (_receivedIdLock) {
locked_cleanReceivedIds(now); locked_cleanReceivedIds(now);
} }
@ -122,5 +130,4 @@ public class MessageValidator {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Cleaned out " + toRemoveDates.size() + " expired messageIds, leaving " + _receivedIds.size() + " remaining"); _log.info("Cleaned out " + toRemoveDates.size() + " expired messageIds, leaving " + _receivedIds.size() + " remaining");
} }
} }

View File

@ -23,9 +23,6 @@ import net.i2p.router.networkdb.kademlia.KademliaNetworkDatabaseFacade;
* *
*/ */
public abstract class NetworkDatabaseFacade implements Service { 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. * Return the RouterInfo structures for the routers closest to the given key.
* At most maxNumRouters will be returned * At most maxNumRouters will be returned
@ -54,14 +51,16 @@ public abstract class NetworkDatabaseFacade implements Service {
class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade { class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
private Map _routers; private Map _routers;
private RouterContext _context;
public DummyNetworkDatabaseFacade() { public DummyNetworkDatabaseFacade(RouterContext ctx) {
_routers = new HashMap(); _routers = new HashMap();
_context = ctx;
} }
public void shutdown() {} public void shutdown() {}
public void startup() { public void startup() {
RouterInfo info = Router.getInstance().getRouterInfo(); RouterInfo info = _context.router().getRouterInfo();
_routers.put(info.getIdentity().getHash(), info); _routers.put(info.getIdentity().getHash(), info);
} }
@ -70,9 +69,9 @@ class DummyNetworkDatabaseFacade extends NetworkDatabaseFacade {
public void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) { public void lookupRouterInfo(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {
RouterInfo info = lookupRouterInfoLocally(key); RouterInfo info = lookupRouterInfoLocally(key);
if (info == null) if (info == null)
JobQueue.getInstance().addJob(onFailedLookupJob); _context.jobQueue().addJob(onFailedLookupJob);
else else
JobQueue.getInstance().addJob(onFindJob); _context.jobQueue().addJob(onFindJob);
} }
public RouterInfo lookupRouterInfoLocally(Hash key) { return (RouterInfo)_routers.get(key); } public RouterInfo lookupRouterInfoLocally(Hash key) { return (RouterInfo)_routers.get(key); }
public void publish(LeaseSet localLeaseSet) {} public void publish(LeaseSet localLeaseSet) {}

View File

@ -32,7 +32,8 @@ import net.i2p.util.Log;
* *
*/ */
public class OutNetMessage { public class OutNetMessage {
private final static Log _log = new Log(OutNetMessage.class); private Log _log;
private RouterContext _context;
private RouterInfo _target; private RouterInfo _target;
private I2NPMessage _message; private I2NPMessage _message;
private long _messageSize; private long _messageSize;
@ -55,7 +56,9 @@ public class OutNetMessage {
*/ */
private List _timestampOrder; private List _timestampOrder;
public OutNetMessage() { public OutNetMessage(RouterContext context) {
_context = context;
_log = context.logManager().getLog(OutNetMessage.class);
setTarget(null); setTarget(null);
_message = null; _message = null;
_messageSize = 0; _messageSize = 0;
@ -71,13 +74,13 @@ public class OutNetMessage {
_failedTransports = new HashSet(); _failedTransports = new HashSet();
_sendBegin = 0; _sendBegin = 0;
_createdBy = new Exception("Created by"); _createdBy = new Exception("Created by");
_created = Clock.getInstance().now(); _created = context.clock().now();
timestamp("Created"); timestamp("Created");
} }
public void timestamp(String eventName) { public void timestamp(String eventName) {
synchronized (_timestamps) { synchronized (_timestamps) {
_timestamps.put(eventName, new Long(Clock.getInstance().now())); _timestamps.put(eventName, new Long(_context.clock().now()));
_timestampOrder.add(eventName); _timestampOrder.add(eventName);
} }
} }
@ -199,10 +202,10 @@ public class OutNetMessage {
/** when did the sending process begin */ /** when did the sending process begin */
public long getSendBegin() { return _sendBegin; } 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 getCreated() { return _created; }
public long getLifetime() { return Clock.getInstance().now() - _created; } public long getLifetime() { return _context.clock().now() - _created; }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);

View File

@ -26,13 +26,12 @@ import net.i2p.util.Log;
* *
*/ */
public class OutNetMessagePool { public class OutNetMessagePool {
private final static Log _log = new Log(OutNetMessagePool.class); private Log _log;
private static OutNetMessagePool _instance = new OutNetMessagePool(); private RouterContext _context;
public static OutNetMessagePool getInstance() { return _instance; }
private TreeMap _messageLists; // priority --> List of OutNetMessage objects, where HIGHEST priority first
private OutNetMessagePool() { public OutNetMessagePool(RouterContext context) {
_messageLists = new TreeMap(new ReverseIntegerComparator()); _context = context;
_log = _context.logManager().getLog(OutNetMessagePool.class);
} }
/** /**
@ -40,20 +39,8 @@ public class OutNetMessagePool {
* *
*/ */
public OutNetMessage getNext() { 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;
} }
}
/** /**
* Add a new message to the pool * Add a new message to the pool
@ -62,24 +49,14 @@ public class OutNetMessagePool {
public void add(OutNetMessage msg) { public void add(OutNetMessage msg) {
boolean valid = validate(msg); boolean valid = validate(msg);
if (!valid) return; if (!valid) return;
if (true) { // skip the pool
MessageSelector selector = msg.getReplySelector(); MessageSelector selector = msg.getReplySelector();
if (selector != null) { if (selector != null) {
OutboundMessageRegistry.getInstance().registerPending(msg); _context.messageRegistry().registerPending(msg);
} }
CommSystemFacade.getInstance().processMessage(msg); _context.commSystem().processMessage(msg);
return; 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);
}
}
private boolean validate(OutNetMessage msg) { private boolean validate(OutNetMessage msg) {
if (msg == null) return false; if (msg == null) return false;
if (msg.getMessage() == null) { if (msg.getMessage() == null) {
@ -94,7 +71,7 @@ public class OutNetMessagePool {
_log.warn("Priority less than 0? sounds like nonsense to me... " + msg, new Exception("Negative priority")); _log.warn("Priority less than 0? sounds like nonsense to me... " + msg, new Exception("Negative priority"));
return false; return false;
} }
if (msg.getExpiration() <= Clock.getInstance().now()) { if (msg.getExpiration() <= _context.clock().now()) {
_log.error("Already expired! wtf: " + msg, new Exception("Expired message")); _log.error("Already expired! wtf: " + msg, new Exception("Expired message"));
return false; return false;
} }
@ -106,43 +83,14 @@ public class OutNetMessagePool {
* *
*/ */
public void clearExpired() { public void clearExpired() {
long now = Clock.getInstance().now(); // noop
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);
}
} }
/** /**
* Retrieve the number of messages, regardless of priority. * Retrieve the number of messages, regardless of priority.
* *
*/ */
public int getCount() { public int getCount() { return 0; }
int size = 0;
synchronized (_messageLists) {
for (Iterator iter = _messageLists.values().iterator(); iter.hasNext(); ) {
List lst = (List)iter.next();
size += lst.size();
}
}
return size;
}
/** /**
* Retrieve the number of messages at the given priority. This can be used for * Retrieve the number of messages at the given priority. This can be used for
@ -150,37 +98,9 @@ public class OutNetMessagePool {
* where all of these 'spare' messages are of the same priority. * where all of these 'spare' messages are of the same priority.
* *
*/ */
public int getCount(int priority) { public int getCount(int priority) { return 0; }
synchronized (_messageLists) {
Integer pri = new Integer(priority);
List messages = (List)_messageLists.get(pri);
if (messages == null)
return 0;
else
return messages.size();
}
}
public void dumpPoolInfo() { public void dumpPoolInfo() { return; }
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());
}
private static class ReverseIntegerComparator implements Comparator { private static class ReverseIntegerComparator implements Comparator {
public int compare(Object lhs, Object rhs) { public int compare(Object lhs, Object rhs) {

View File

@ -18,23 +18,19 @@ import net.i2p.router.peermanager.PeerManagerFacadeImpl;
* includes periodically queueing up outbound messages to the peers to test them. * includes periodically queueing up outbound messages to the peers to test them.
* *
*/ */
public abstract class PeerManagerFacade implements Service { public interface PeerManagerFacade extends Service {
private static PeerManagerFacade _instance = new PeerManagerFacadeImpl();
public static PeerManagerFacade getInstance() { return _instance; }
/** /**
* Select peers from the manager's existing routing tables according to * Select peers from the manager's existing routing tables according to
* the specified criteria. This call DOES block. * the specified criteria. This call DOES block.
* *
* @return List of Hash objects of the RouterIdentity for matching peers * @return List of Hash objects of the RouterIdentity for matching peers
*/ */
public abstract List selectPeers(PeerSelectionCriteria criteria); public List selectPeers(PeerSelectionCriteria criteria);
public String renderStatusHTML() { return ""; }
} }
class DummyPeerManagerFacade extends PeerManagerFacade { class DummyPeerManagerFacade implements PeerManagerFacade {
public void shutdown() {} public void shutdown() {}
public void startup() {} public void startup() {}
public String renderStatusHTML() { return ""; }
public List selectPeers(PeerSelectionCriteria criteria) { return null; } public List selectPeers(PeerSelectionCriteria criteria) { return null; }
} }

View File

@ -11,71 +11,64 @@ package net.i2p.router;
import java.util.Properties; import java.util.Properties;
import net.i2p.data.Hash; 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. * 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. * 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 * 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 * 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 * 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 * 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 * 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 * Note that the peer participated in a tunnel that failed. Its failure may not have
* been the peer's fault however. * 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 * 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 * Note that the peer was unable to reply to a db lookup - either with data or with
* a lookupReply redirecting the user elsewhere * 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 * 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 * 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 * 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 * 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 * 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) * 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 * Note that we were unable to confirm a successful send of db data to
* the peer, at least not within our timeout period * 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 * Note that the local router received a reference to the given peer, either
* through an explicit dbStore or in a dbLookupReply * 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 * Note that the router received a message from the given peer on the specified
@ -126,8 +119,8 @@ public abstract class ProfileManager {
* available * 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 */ /** 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);
} }

View File

@ -54,14 +54,14 @@ import net.i2p.util.RandomSource;
* *
*/ */
public class Router { public class Router {
private final static Log _log = new Log(Router.class); private Log _log;
private final static Router _instance = new Router(); private RouterContext _context;
public static Router getInstance() { return _instance; }
private Properties _config; private Properties _config;
private String _configFilename; private String _configFilename;
private RouterInfo _routerInfo; private RouterInfo _routerInfo;
private long _started; private long _started;
private boolean _higherVersionSeen; private boolean _higherVersionSeen;
private SessionKeyPersistenceHelper _sessionKeyPersistenceHelper;
public final static String PROP_CONFIG_FILE = "router.configLocation"; 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 = "router.keys.location";
public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys"; public final static String PROP_KEYS_FILENAME_DEFAULT = "router.keys";
private Router() { public Router() {
_config = new Properties();
_configFilename = System.getProperty(PROP_CONFIG_FILE, "router.config");
_routerInfo = null;
_higherVersionSeen = false;
// grumble about sun's java caching DNS entries *forever* // grumble about sun's java caching DNS entries *forever*
System.setProperty("sun.net.inetaddr.ttl", "0"); System.setProperty("sun.net.inetaddr.ttl", "0");
System.setProperty("networkaddress.cache.ttl", "0"); System.setProperty("networkaddress.cache.ttl", "0");
// (no need for keepalive) // (no need for keepalive)
System.setProperty("http.keepAlive", "false"); 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; } public String getConfigFilename() { return _configFilename; }
@ -97,7 +100,7 @@ public class Router {
public void setRouterInfo(RouterInfo info) { public void setRouterInfo(RouterInfo info) {
_routerInfo = info; _routerInfo = info;
if (info != null) 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; } public long getWhenStarted() { return _started; }
/** wall clock uptime */ /** 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() { private void runRouter() {
_started = Clock.getInstance().now(); _started = _context.clock().now();
Runtime.getRuntime().addShutdownHook(new ShutdownHook()); Runtime.getRuntime().addShutdownHook(new ShutdownHook());
I2PThread.setOOMEventListener(new I2PThread.OOMEventListener() { I2PThread.setOOMEventListener(new I2PThread.OOMEventListener() {
public void outOfMemory(OutOfMemoryError oom) { public void outOfMemory(OutOfMemoryError oom) {
@ -123,21 +126,22 @@ public class Router {
}); });
setupHandlers(); setupHandlers();
startupQueue(); startupQueue();
JobQueue.getInstance().addJob(new CoallesceStatsJob()); _context.jobQueue().addJob(new CoallesceStatsJob());
JobQueue.getInstance().addJob(new UpdateRoutingKeyModifierJob()); _context.jobQueue().addJob(new UpdateRoutingKeyModifierJob());
warmupCrypto(); warmupCrypto();
SessionKeyPersistenceHelper.getInstance().startup(); _sessionKeyPersistenceHelper.startup();
JobQueue.getInstance().addJob(new StartupJob()); _context.jobQueue().addJob(new StartupJob(_context));
} }
/** /**
* coallesce the stats framework every minute * 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 String getName() { return "Coallesce stats"; }
public void runJob() { public void runJob() {
StatManager.getInstance().coallesceStats(); Router.this._context.statManager().coallesceStats();
requeue(60*1000); 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 * This is done here because we want to make sure the key is updated before anyone
* uses it. * uses it.
*/ */
private final static class UpdateRoutingKeyModifierJob extends JobImpl { private final class UpdateRoutingKeyModifierJob extends JobImpl {
private Calendar _cal = new GregorianCalendar(TimeZone.getTimeZone("GMT")); private Calendar _cal = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
public UpdateRoutingKeyModifierJob() { super(Router.this._context); }
public String getName() { return "Update Routing Key Modifier"; } public String getName() { return "Update Routing Key Modifier"; }
public void runJob() { public void runJob() {
RoutingKeyGenerator.getInstance().generateDateBasedModData(); Router.this._context.routingKeyGenerator().generateDateBasedModData();
requeue(getTimeTillMidnight()); requeue(getTimeTillMidnight());
} }
private long getTimeTillMidnight() { private long getTimeTillMidnight() {
long now = Clock.getInstance().now(); long now = Router.this._context.clock().now();
_cal.setTime(new Date(now)); _cal.setTime(new Date(now));
_cal.add(Calendar.DATE, 1); _cal.add(Calendar.DATE, 1);
_cal.set(Calendar.HOUR_OF_DAY, 0); _cal.set(Calendar.HOUR_OF_DAY, 0);
@ -175,18 +180,18 @@ public class Router {
} }
private void warmupCrypto() { private void warmupCrypto() {
RandomSource.getInstance().nextBoolean(); _context.random().nextBoolean();
new DHSessionKeyBuilder(); // load the class so it starts the precalc process new DHSessionKeyBuilder(); // load the class so it starts the precalc process
} }
private void startupQueue() { private void startupQueue() {
JobQueue.getInstance().runQueue(1); _context.jobQueue().runQueue(1);
} }
private void setupHandlers() { private void setupHandlers() {
InNetMessagePool.getInstance().registerHandlerJobBuilder(GarlicMessage.MESSAGE_TYPE, new GarlicMessageHandler()); _context.inNetMessagePool().registerHandlerJobBuilder(GarlicMessage.MESSAGE_TYPE, new GarlicMessageHandler(_context));
InNetMessagePool.getInstance().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler()); _context.inNetMessagePool().registerHandlerJobBuilder(TunnelMessage.MESSAGE_TYPE, new TunnelMessageHandler(_context));
InNetMessagePool.getInstance().registerHandlerJobBuilder(SourceRouteReplyMessage.MESSAGE_TYPE, new SourceRouteReplyMessageHandler()); _context.inNetMessagePool().registerHandlerJobBuilder(SourceRouteReplyMessage.MESSAGE_TYPE, new SourceRouteReplyMessageHandler(_context));
} }
public String renderStatusHTML() { public String renderStatusHTML() {
@ -214,9 +219,9 @@ public class Router {
if ( (_routerInfo != null) && (_routerInfo.getIdentity() != null) ) if ( (_routerInfo != null) && (_routerInfo.getIdentity() != null) )
buf.append("<b>Router: </b> ").append(_routerInfo.getIdentity().getHash().toBase64()).append("<br />\n"); buf.append("<b>Router: </b> ").append(_routerInfo.getIdentity().getHash().toBase64()).append("<br />\n");
buf.append("<b>As of: </b> ").append(new Date(Clock.getInstance().now())).append(" (uptime: ").append(DataHelper.formatDuration(getUptime())).append(") <br />\n"); buf.append("<b>As of: </b> ").append(new Date(_context.clock().now())).append(" (uptime: ").append(DataHelper.formatDuration(getUptime())).append(") <br />\n");
buf.append("<b>Started on: </b> ").append(new Date(getWhenStarted())).append("<br />\n"); buf.append("<b>Started on: </b> ").append(new Date(getWhenStarted())).append("<br />\n");
buf.append("<b>Clock offset: </b> ").append(Clock.getInstance().getOffset()).append("ms (OS time: ").append(new Date(Clock.getInstance().now() - Clock.getInstance().getOffset())).append(")<br />\n"); buf.append("<b>Clock offset: </b> ").append(_context.clock().getOffset()).append("ms (OS time: ").append(new Date(_context.clock().now() - _context.clock().getOffset())).append(")<br />\n");
long tot = Runtime.getRuntime().totalMemory()/1024; long tot = Runtime.getRuntime().totalMemory()/1024;
long free = Runtime.getRuntime().freeMemory()/1024; long free = Runtime.getRuntime().freeMemory()/1024;
buf.append("<b>Memory:</b> In use: ").append((tot-free)).append("KB Free: ").append(free).append("KB <br />\n"); buf.append("<b>Memory:</b> In use: ").append((tot-free)).append("KB Free: ").append(free).append("KB <br />\n");
@ -225,8 +230,8 @@ public class Router {
buf.append("<b><font color=\"red\">HIGHER VERSION SEEN</font><b> - please <a href=\"http://i2p.dnsalias.net/\">check</a> to see if there is a new release out<br />\n"); buf.append("<b><font color=\"red\">HIGHER VERSION SEEN</font><b> - please <a href=\"http://i2p.dnsalias.net/\">check</a> to see if there is a new release out<br />\n");
buf.append("<hr /><a name=\"bandwidth\"> </a><h2>Bandwidth</h2>\n"); buf.append("<hr /><a name=\"bandwidth\"> </a><h2>Bandwidth</h2>\n");
long sent = BandwidthLimiter.getInstance().getTotalSendBytes(); long sent = _context.bandwidthLimiter().getTotalSendBytes();
long received = BandwidthLimiter.getInstance().getTotalReceiveBytes(); long received = _context.bandwidthLimiter().getTotalReceiveBytes();
buf.append("<ul>"); buf.append("<ul>");
buf.append("<li> ").append(sent).append(" bytes sent, "); buf.append("<li> ").append(sent).append(" bytes sent, ");
@ -235,7 +240,7 @@ public class Router {
DecimalFormat fmt = new DecimalFormat("##0.00"); DecimalFormat fmt = new DecimalFormat("##0.00");
// we use the unadjusted time, since thats what getWhenStarted is based off // we use the unadjusted time, since thats what getWhenStarted is based off
long lifetime = Clock.getInstance().now()-Clock.getInstance().getOffset() - getWhenStarted(); long lifetime = _context.clock().now()-_context.clock().getOffset() - getWhenStarted();
lifetime /= 1000; lifetime /= 1000;
if ( (sent > 0) && (received > 0) ) { if ( (sent > 0) && (received > 0) ) {
double sendKBps = sent / (lifetime*1024.0); double sendKBps = sent / (lifetime*1024.0);
@ -246,7 +251,7 @@ public class Router {
buf.append("</li>"); buf.append("</li>");
} }
RateStat sendRate = StatManager.getInstance().getRate("transport.sendMessageSize"); RateStat sendRate = _context.statManager().getRate("transport.sendMessageSize");
for (int i = 0; i < sendRate.getPeriods().length; i++) { for (int i = 0; i < sendRate.getPeriods().length; i++) {
Rate rate = sendRate.getRate(sendRate.getPeriods()[i]); Rate rate = sendRate.getRate(sendRate.getPeriods()[i]);
double bytes = rate.getLastTotalValue() + rate.getCurrentTotalValue(); double bytes = rate.getLastTotalValue() + rate.getCurrentTotalValue();
@ -280,7 +285,7 @@ public class Router {
buf.append("</li>"); buf.append("</li>");
} }
RateStat receiveRate = StatManager.getInstance().getRate("transport.receiveMessageSize"); RateStat receiveRate = _context.statManager().getRate("transport.receiveMessageSize");
for (int i = 0; i < receiveRate.getPeriods().length; i++) { for (int i = 0; i < receiveRate.getPeriods().length; i++) {
Rate rate = receiveRate.getRate(receiveRate.getPeriods()[i]); Rate rate = receiveRate.getRate(receiveRate.getPeriods()[i]);
double bytes = rate.getLastTotalValue() + rate.getCurrentTotalValue(); double bytes = rate.getLastTotalValue() + rate.getCurrentTotalValue();
@ -321,23 +326,23 @@ public class Router {
buf.append("\n"); buf.append("\n");
buf.append("<hr /><a name=\"clients\"> </a>\n"); buf.append("<hr /><a name=\"clients\"> </a>\n");
buf.append(ClientManagerFacade.getInstance().renderStatusHTML()); buf.append(_context.clientManager().renderStatusHTML());
buf.append("\n<hr /><a name=\"transports\"> </a>\n"); buf.append("\n<hr /><a name=\"transports\"> </a>\n");
buf.append(CommSystemFacade.getInstance().renderStatusHTML()); buf.append(_context.commSystem().renderStatusHTML());
buf.append("\n<hr /><a name=\"profiles\"> </a>\n"); buf.append("\n<hr /><a name=\"profiles\"> </a>\n");
buf.append(PeerManagerFacade.getInstance().renderStatusHTML()); buf.append(_context.peerManager().renderStatusHTML());
buf.append("\n<hr /><a name=\"tunnels\"> </a>\n"); buf.append("\n<hr /><a name=\"tunnels\"> </a>\n");
buf.append(TunnelManagerFacade.getInstance().renderStatusHTML()); buf.append(_context.tunnelManager().renderStatusHTML());
buf.append("\n<hr /><a name=\"jobs\"> </a>\n"); buf.append("\n<hr /><a name=\"jobs\"> </a>\n");
buf.append(JobQueue.getInstance().renderStatusHTML()); buf.append(_context.jobQueue().renderStatusHTML());
buf.append("\n<hr /><a name=\"shitlist\"> </a>\n"); buf.append("\n<hr /><a name=\"shitlist\"> </a>\n");
buf.append(Shitlist.getInstance().renderStatusHTML()); buf.append(_context.shitlist().renderStatusHTML());
buf.append("\n<hr /><a name=\"pending\"> </a>\n"); buf.append("\n<hr /><a name=\"pending\"> </a>\n");
buf.append(OutboundMessageRegistry.getInstance().renderStatusHTML()); buf.append(_context.messageRegistry().renderStatusHTML());
buf.append("\n<hr /><a name=\"netdb\"> </a>\n"); buf.append("\n<hr /><a name=\"netdb\"> </a>\n");
buf.append(NetworkDatabaseFacade.getInstance().renderStatusHTML()); buf.append(_context.netDb().renderStatusHTML());
buf.append("\n<hr /><a name=\"logs\"> </a>\n"); buf.append("\n<hr /><a name=\"logs\"> </a>\n");
List msgs = LogConsoleBuffer.getInstance().getMostRecentMessages(); List msgs = _context.logManager().getBuffer().getMostRecentMessages();
buf.append("\n<h2>Most recent console messages:</h2><table border=\"1\">\n"); buf.append("\n<h2>Most recent console messages:</h2><table border=\"1\">\n");
for (Iterator iter = msgs.iterator(); iter.hasNext(); ) { for (Iterator iter = msgs.iterator(); iter.hasNext(); ) {
String msg = (String)iter.next(); String msg = (String)iter.next();
@ -350,27 +355,28 @@ public class Router {
} }
public void shutdown() { public void shutdown() {
try { JobQueue.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the job queue", t); } try { _context.jobQueue().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the job queue", t); }
try { StatisticsManager.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the stats manager", t); } try { _context.statPublisher().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the stats manager", t); }
try { ClientManagerFacade.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the client manager", t); } try { _context.clientManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the client manager", t); }
try { TunnelManagerFacade.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the tunnel manager", t); } try { _context.tunnelManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the tunnel manager", t); }
try { NetworkDatabaseFacade.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the networkDb", t); } try { _context.netDb().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the networkDb", t); }
try { CommSystemFacade.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the comm system", t); } try { _context.commSystem().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the comm system", t); }
try { PeerManagerFacade.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the peer manager", t); } try { _context.peerManager().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the peer manager", t); }
try { SessionKeyPersistenceHelper.getInstance().shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); } try { _sessionKeyPersistenceHelper.shutdown(); } catch (Throwable t) { _log.log(Log.CRIT, "Error shutting down the session key manager", t); }
dumpStats(); dumpStats();
_log.log(Log.CRIT, "Shutdown complete", new Exception("Shutdown")); _log.log(Log.CRIT, "Shutdown complete", new Exception("Shutdown"));
try { LogManager.getInstance().shutdown(); } catch (Throwable t) { } try { _context.logManager().shutdown(); } catch (Throwable t) { }
try { Thread.sleep(1000); } catch (InterruptedException ie) {} try { Thread.sleep(1000); } catch (InterruptedException ie) {}
Runtime.getRuntime().halt(-1); Runtime.getRuntime().halt(-1);
} }
private void dumpStats() { private void dumpStats() {
_log.log(Log.CRIT, "Lifetime stats:\n\n" + StatsGenerator.generateStatsPage()); //_log.log(Log.CRIT, "Lifetime stats:\n\n" + StatsGenerator.generateStatsPage());
} }
public static void main(String args[]) { public static void main(String args[]) {
Router.getInstance().runRouter(); Router r = new Router();
r.runRouter();
} }
private class ShutdownHook extends Thread { private class ShutdownHook extends Thread {
@ -381,17 +387,18 @@ public class Router {
} }
/** update the router.info file whenever its, er, updated */ /** update the router.info file whenever its, er, updated */
private static class PersistRouterInfoJob extends JobImpl { private class PersistRouterInfoJob extends JobImpl {
public PersistRouterInfoJob() { super(Router.this._context); }
public String getName() { return "Persist Updated Router Information"; } public String getName() { return "Persist Updated Router Information"; }
public void runJob() { public void runJob() {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Persisting updated router info"); _log.debug("Persisting updated router info");
String infoFilename = Router.getInstance().getConfigSetting(PROP_INFO_FILENAME); String infoFilename = getConfigSetting(PROP_INFO_FILENAME);
if (infoFilename == null) if (infoFilename == null)
infoFilename = PROP_INFO_FILENAME_DEFAULT; infoFilename = PROP_INFO_FILENAME_DEFAULT;
RouterInfo info = Router.getInstance().getRouterInfo(); RouterInfo info = getRouterInfo();
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {

View File

@ -0,0 +1,465 @@
package net.i2p.router;
import net.i2p.data.Hash;
import net.i2p.router.client.ClientManagerFacadeImpl;
import net.i2p.router.transport.OutboundMessageRegistry;
import net.i2p.router.networkdb.kademlia.KademliaNetworkDatabaseFacade;
import net.i2p.router.transport.CommSystemFacadeImpl;
import net.i2p.router.transport.BandwidthLimiter;
import net.i2p.router.transport.TrivialBandwidthLimiter;
import net.i2p.router.tunnelmanager.PoolingTunnelManagerFacade;
import net.i2p.router.peermanager.ProfileOrganizer;
import net.i2p.router.peermanager.PeerManagerFacadeImpl;
import net.i2p.router.peermanager.ProfileManagerImpl;
import net.i2p.router.peermanager.Calculator;
import net.i2p.router.peermanager.IsFailingCalculator;
import net.i2p.router.peermanager.ReliabilityCalculator;
import net.i2p.router.peermanager.SpeedCalculator;
import net.i2p.router.peermanager.IntegrationCalculator;
import net.i2p.I2PAppContext;
/**
* Build off the core I2P context to provide a root for a router instance to
* coordinate its resources. Router instances themselves should be sure to have
* their own RouterContext, and rooting off of it will allow multiple routers to
* operate in the same JVM without conflict (e.g. sessionTags wont get
* intermingled, nor will their netDbs, jobQueues, or bandwidth limiters).
*
*/
public class RouterContext extends I2PAppContext {
private Router _router;
private ClientManagerFacade _clientManagerFacade;
private ClientMessagePool _clientMessagePool;
private JobQueue _jobQueue;
private InNetMessagePool _inNetMessagePool;
private OutNetMessagePool _outNetMessagePool;
private MessageHistory _messageHistory;
private OutboundMessageRegistry _messageRegistry;
private NetworkDatabaseFacade _netDb;
private KeyManager _keyManager;
private CommSystemFacade _commSystem;
private ProfileOrganizer _profileOrganizer;
private PeerManagerFacade _peerManagerFacade;
private ProfileManager _profileManager;
private BandwidthLimiter _bandwidthLimiter;
private TunnelManagerFacade _tunnelManager;
private StatisticsManager _statPublisher;
private Shitlist _shitlist;
private MessageValidator _messageValidator;
private Calculator _isFailingCalc;
private Calculator _integrationCalc;
private Calculator _speedCalc;
private Calculator _reliabilityCalc;
public RouterContext(Router router) {
super();
_router = router;
initAll();
}
private void initAll() {
_clientManagerFacade = new ClientManagerFacadeImpl(this);
_clientMessagePool = new ClientMessagePool(this);
_jobQueue = new JobQueue(this);
_inNetMessagePool = new InNetMessagePool(this);
_outNetMessagePool = new OutNetMessagePool(this);
_messageHistory = new MessageHistory(this);
_messageRegistry = new OutboundMessageRegistry(this);
_netDb = new KademliaNetworkDatabaseFacade(this);
_keyManager = new KeyManager(this);
_commSystem = new CommSystemFacadeImpl(this);
_profileOrganizer = new ProfileOrganizer(this);
_peerManagerFacade = new PeerManagerFacadeImpl(this);
_profileManager = new ProfileManagerImpl(this);
_bandwidthLimiter = new TrivialBandwidthLimiter(this);
_tunnelManager = new PoolingTunnelManagerFacade(this);
_statPublisher = new StatisticsManager(this);
_shitlist = new Shitlist(this);
_messageValidator = new MessageValidator(this);
_isFailingCalc = new IsFailingCalculator(this);
_integrationCalc = new IntegrationCalculator(this);
_speedCalc = new SpeedCalculator(this);
_reliabilityCalc = new ReliabilityCalculator(this);
}
/** what router is this context working for? */
public Router router() { return _router; }
/** convenience method for querying the router's ident */
public Hash routerHash() { return _router.getRouterInfo().getIdentity().getHash(); }
/**
* How are we coordinating clients for the router?
*/
public ClientManagerFacade clientManager() { return _clientManagerFacade; }
/**
* Where do we toss messages for the clients (and where do we get client messages
* to forward on from)?
*/
public ClientMessagePool clientMessagePool() { return _clientMessagePool; }
/**
* Where do we get network messages from (aka where does the comm system dump what
* it reads)?
*/
public InNetMessagePool inNetMessagePool() { return _inNetMessagePool; }
/**
* Where do we put messages that the router wants to forwards onto the network?
*/
public OutNetMessagePool outNetMessagePool() { return _outNetMessagePool; }
/**
* Tracker component for monitoring what messages are wrapped in what containers
* and how they proceed through the network. This is fully for debugging, as when
* a large portion of the network tracks their messages through this messageHistory
* and submits their logs, we can correlate them and watch as messages flow from
* hop to hop.
*/
public MessageHistory messageHistory() { return _messageHistory; }
/**
* The registry is used by outbound messages to wait for replies.
*/
public OutboundMessageRegistry messageRegistry() { return _messageRegistry; }
/**
* Our db cache
*/
public NetworkDatabaseFacade netDb() { return _netDb; }
/**
* The actual driver of the router, where all jobs are enqueued and processed.
*/
public JobQueue jobQueue() { return _jobQueue; }
/**
* Coordinates the router's ElGamal and DSA keys, as well as any keys given
* to it by clients as part of a LeaseSet.
*/
public KeyManager keyManager() { return _keyManager; }
/**
* How do we pass messages from our outNetMessagePool to another router
*/
public CommSystemFacade commSystem() { return _commSystem; }
/**
* Organize the peers we know about into various tiers, profiling their
* performance and sorting them accordingly.
*/
public ProfileOrganizer profileOrganizer() { return _profileOrganizer; }
/**
* Minimal interface for selecting peers for various tasks based on given
* criteria. This is kept seperate from the profile organizer since this
* logic is independent of how the peers are organized (or profiled even).
*/
public PeerManagerFacade peerManager() { return _peerManagerFacade; }
/**
* Expose a simple API for various router components to take note of
* particular events that a peer enacts (sends us a message, agrees to
* participate in a tunnel, etc).
*/
public ProfileManager profileManager() { return _profileManager; }
/**
* Coordinate this router's bandwidth limits
*/
public BandwidthLimiter bandwidthLimiter() { return _bandwidthLimiter; }
/**
* Coordinate this router's tunnels (its pools, participation, backup, etc).
* Any configuration for the tunnels is rooted from the context's properties
*/
public TunnelManagerFacade tunnelManager() { return _tunnelManager; }
/**
* If the router is configured to, gather up some particularly tasty morsels
* regarding the stats managed and offer to publish them into the routerInfo.
*/
public StatisticsManager statPublisher() { return _statPublisher; }
/**
* who does this peer hate?
*/
public Shitlist shitlist() { return _shitlist; }
/**
* The router keeps track of messages it receives to prevent duplicates, as
* well as other criteria for "validity".
*/
public MessageValidator messageValidator() { return _messageValidator; }
/** how do we rank the failure of profiles? */
public Calculator isFailingCalculator() { return _isFailingCalc; }
/** how do we rank the integration of profiles? */
public Calculator integrationCalculator() { return _integrationCalc; }
/** how do we rank the speed of profiles? */
public Calculator speedCalculator() { return _speedCalc; }
/** how do we rank the reliability of profiles? */
public Calculator reliabilityCalculator() { return _reliabilityCalc; }
}
/*
public class RouterContext extends I2PAppContext {
private Router _router;
private ClientManagerFacade _clientManagerFacade;
private ClientMessagePool _clientMessagePool;
private JobQueue _jobQueue;
private InNetMessagePool _inNetMessagePool;
private OutNetMessagePool _outNetMessagePool;
private MessageHistory _messageHistory;
private OutboundMessageRegistry _messageRegistry;
private NetworkDatabaseFacade _netDb;
private KeyManager _keyManager;
private CommSystemFacade _commSystem;
private ProfileOrganizer _profileOrganizer;
private PeerManagerFacade _peerManagerFacade;
private ProfileManager _profileManager;
private BandwidthLimiter _bandwidthLimiter;
private TunnelManagerFacade _tunnelManager;
private StatisticsManager _statPublisher;
private Shitlist _shitlist;
private MessageValidator _messageValidator;
private volatile boolean _clientManagerFacadeInitialized;
private volatile boolean _clientMessagePoolInitialized;
private volatile boolean _jobQueueInitialized;
private volatile boolean _inNetMessagePoolInitialized;
private volatile boolean _outNetMessagePoolInitialized;
private volatile boolean _messageHistoryInitialized;
private volatile boolean _messageRegistryInitialized;
private volatile boolean _netDbInitialized;
private volatile boolean _peerSelectorInitialized;
private volatile boolean _keyManagerInitialized;
private volatile boolean _commSystemInitialized;
private volatile boolean _profileOrganizerInitialized;
private volatile boolean _profileManagerInitialized;
private volatile boolean _peerManagerFacadeInitialized;
private volatile boolean _bandwidthLimiterInitialized;
private volatile boolean _tunnelManagerInitialized;
private volatile boolean _statPublisherInitialized;
private volatile boolean _shitlistInitialized;
private volatile boolean _messageValidatorInitialized;
private Calculator _isFailingCalc = new IsFailingCalculator(this);
private Calculator _integrationCalc = new IntegrationCalculator(this);
private Calculator _speedCalc = new SpeedCalculator(this);
private Calculator _reliabilityCalc = new ReliabilityCalculator(this);
public Calculator isFailingCalculator() { return _isFailingCalc; }
public Calculator integrationCalculator() { return _integrationCalc; }
public Calculator speedCalculator() { return _speedCalc; }
public Calculator reliabilityCalculator() { return _reliabilityCalc; }
public RouterContext(Router router) {
super();
_router = router;
}
public Router router() { return _router; }
public Hash routerHash() { return _router.getRouterInfo().getIdentity().getHash(); }
public ClientManagerFacade clientManager() {
if (!_clientManagerFacadeInitialized) initializeClientManagerFacade();
return _clientManagerFacade;
}
private void initializeClientManagerFacade() {
synchronized (this) {
if (_clientManagerFacade == null) {
_clientManagerFacade = new ClientManagerFacadeImpl(this);
}
_clientManagerFacadeInitialized = true;
}
}
public ClientMessagePool clientMessagePool() {
if (!_clientMessagePoolInitialized) initializeClientMessagePool();
return _clientMessagePool;
}
private void initializeClientMessagePool() {
synchronized (this) {
if (_clientMessagePool == null) {
_clientMessagePool = new ClientMessagePool(this);
}
_clientMessagePoolInitialized = true;
}
}
public InNetMessagePool inNetMessagePool() {
if (!_inNetMessagePoolInitialized) initializeInNetMessagePool();
return _inNetMessagePool;
}
private void initializeInNetMessagePool() {
synchronized (this) {
if (_inNetMessagePool == null) {
_inNetMessagePool = new InNetMessagePool(this);
}
_inNetMessagePoolInitialized = true;
}
}
public OutNetMessagePool outNetMessagePool() {
if (!_outNetMessagePoolInitialized) initializeOutNetMessagePool();
return _outNetMessagePool;
}
private void initializeOutNetMessagePool() {
synchronized (this) {
if (_outNetMessagePool == null) {
_outNetMessagePool = new OutNetMessagePool(this);
}
_outNetMessagePoolInitialized = true;
}
}
public MessageHistory messageHistory() {
if (!_messageHistoryInitialized) initializeMessageHistory();
return _messageHistory;
}
private void initializeMessageHistory() {
synchronized (this) {
if (_messageHistory == null) {
_messageHistory = new MessageHistory(this);
}
_messageHistoryInitialized = true;
}
}
public OutboundMessageRegistry messageRegistry() {
if (!_messageRegistryInitialized) initializeMessageRegistry();
return _messageRegistry;
}
private void initializeMessageRegistry() {
synchronized (this) {
if (_messageRegistry == null)
_messageRegistry = new OutboundMessageRegistry(this);
_messageRegistryInitialized = true;
}
}
public NetworkDatabaseFacade netDb() {
if (!_netDbInitialized) initializeNetDb();
return _netDb;
}
private void initializeNetDb() {
synchronized (this) {
if (_netDb == null)
_netDb = new KademliaNetworkDatabaseFacade(this);
_netDbInitialized = true;
}
}
public JobQueue jobQueue() {
if (!_jobQueueInitialized) initializeJobQueue();
return _jobQueue;
}
private void initializeJobQueue() {
synchronized (this) {
if (_jobQueue == null) {
_jobQueue= new JobQueue(this);
}
_jobQueueInitialized = true;
}
}
public KeyManager keyManager() {
if (!_keyManagerInitialized) initializeKeyManager();
return _keyManager;
}
private void initializeKeyManager() {
synchronized (this) {
if (_keyManager == null)
_keyManager = new KeyManager(this);
_keyManagerInitialized = true;
}
}
public CommSystemFacade commSystem() {
if (!_commSystemInitialized) initializeCommSystem();
return _commSystem;
}
private void initializeCommSystem() {
synchronized (this) {
if (_commSystem == null)
_commSystem = new CommSystemFacadeImpl(this);
_commSystemInitialized = true;
}
}
public ProfileOrganizer profileOrganizer() {
if (!_profileOrganizerInitialized) initializeProfileOrganizer();
return _profileOrganizer;
}
private void initializeProfileOrganizer() {
synchronized (this) {
if (_profileOrganizer == null)
_profileOrganizer = new ProfileOrganizer(this);
_profileOrganizerInitialized = true;
}
}
public PeerManagerFacade peerManager() {
if (!_peerManagerFacadeInitialized) initializePeerManager();
return _peerManagerFacade;
}
private void initializePeerManager() {
synchronized (this) {
if (_peerManagerFacade == null)
_peerManagerFacade = new PeerManagerFacadeImpl(this);
_peerManagerFacadeInitialized = true;
}
}
public BandwidthLimiter bandwidthLimiter() {
if (!_bandwidthLimiterInitialized) initializeBandwidthLimiter();
return _bandwidthLimiter;
}
private void initializeBandwidthLimiter() {
synchronized (this) {
if (_bandwidthLimiter == null)
_bandwidthLimiter = new TrivialBandwidthLimiter(this);
_bandwidthLimiterInitialized = true;
}
}
public TunnelManagerFacade tunnelManager() {
if (!_tunnelManagerInitialized) initializeTunnelManager();
return _tunnelManager;
}
private void initializeTunnelManager() {
synchronized (this) {
if (_tunnelManager == null)
_tunnelManager = new PoolingTunnelManagerFacade(this);
_tunnelManagerInitialized = true;
}
}
public ProfileManager profileManager() {
if (!_profileManagerInitialized) initializeProfileManager();
return _profileManager;
}
private void initializeProfileManager() {
synchronized (this) {
if (_profileManager == null)
_profileManager = new ProfileManagerImpl(this);
_profileManagerInitialized = true;
}
}
public StatisticsManager statPublisher() {
if (!_statPublisherInitialized) initializeStatPublisher();
return _statPublisher;
}
private void initializeStatPublisher() {
synchronized (this) {
if (_statPublisher == null)
_statPublisher = new StatisticsManager(this);
_statPublisherInitialized = true;
}
}
public Shitlist shitlist() {
if (!_shitlistInitialized) initializeShitlist();
return _shitlist;
}
private void initializeShitlist() {
synchronized (this) {
if (_shitlist == null)
_shitlist = new Shitlist(this);
_shitlistInitialized = true;
}
}
public MessageValidator messageValidator() {
if (!_messageValidatorInitialized) initializeMessageValidator();
return _messageValidator;
}
private void initializeMessageValidator() {
synchronized (this) {
if (_messageValidator == null)
_messageValidator = new MessageValidator(this);
_messageValidatorInitialized = true;
}
}
}
*/

View File

@ -15,18 +15,22 @@ import net.i2p.util.Log;
* *
*/ */
public class SessionKeyPersistenceHelper implements Service { public class SessionKeyPersistenceHelper implements Service {
private final static Log _log = new Log(SessionKeyPersistenceHelper.class); private Log _log;
private static SessionKeyPersistenceHelper _instance = new SessionKeyPersistenceHelper(); private RouterContext _context;
public static SessionKeyPersistenceHelper getInstance() { return _instance; }
private final static long PERSIST_DELAY = 3*60*1000; private final static long PERSIST_DELAY = 3*60*1000;
private final static String SESSION_KEY_FILE = "sessionKeys.dat"; private final static String SESSION_KEY_FILE = "sessionKeys.dat";
public SessionKeyPersistenceHelper(RouterContext context) {
_context = context;
_log = _context.logManager().getLog(SessionKeyPersistenceHelper.class);
}
public void shutdown() { public void shutdown() {
writeState(); writeState();
} }
public void startup() { public void startup() {
SessionKeyManager mgr = SessionKeyManager.getInstance(); SessionKeyManager mgr = _context.sessionKeyManager();
if (mgr instanceof PersistentSessionKeyManager) { if (mgr instanceof PersistentSessionKeyManager) {
PersistentSessionKeyManager manager = (PersistentSessionKeyManager)mgr; PersistentSessionKeyManager manager = (PersistentSessionKeyManager)mgr;
File f = new File(SESSION_KEY_FILE); File f = new File(SESSION_KEY_FILE);
@ -36,19 +40,21 @@ public class SessionKeyPersistenceHelper implements Service {
fin = new FileInputStream(f); fin = new FileInputStream(f);
manager.loadState(fin); manager.loadState(fin);
int expired = manager.aggressiveExpire(); int expired = manager.aggressiveExpire();
_log.debug("Session keys loaded [not error] with " + expired + " sets immediately expired"); if (_log.shouldLog(Log.DEBUG))
_log.debug("Session keys loaded [not error] with " + expired
+ " sets immediately expired");
} catch (Throwable t) { } catch (Throwable t) {
_log.error("Error reading in session key data", t); _log.error("Error reading in session key data", t);
} finally { } finally {
if (fin != null) try { fin.close(); } catch (IOException ioe) {} if (fin != null) try { fin.close(); } catch (IOException ioe) {}
} }
} }
JobQueue.getInstance().addJob(new SessionKeyWriterJob()); _context.jobQueue().addJob(new SessionKeyWriterJob());
} }
} }
private static void writeState() { private void writeState() {
Object o = SessionKeyManager.getInstance(); Object o = _context.sessionKeyManager();
if (!(o instanceof PersistentSessionKeyManager)) { if (!(o instanceof PersistentSessionKeyManager)) {
_log.error("Unable to persist the session key state - manager is " + o.getClass().getName()); _log.error("Unable to persist the session key state - manager is " + o.getClass().getName());
return; return;
@ -79,7 +85,7 @@ public class SessionKeyPersistenceHelper implements Service {
private class SessionKeyWriterJob extends JobImpl { private class SessionKeyWriterJob extends JobImpl {
public SessionKeyWriterJob() { public SessionKeyWriterJob() {
super(); super(SessionKeyPersistenceHelper.this._context);
getTiming().setStartAfter(PERSIST_DELAY); getTiming().setStartAfter(PERSIST_DELAY);
} }
public String getName() { return "Write Session Keys"; } public String getName() { return "Write Session Keys"; }

View File

@ -24,29 +24,35 @@ import net.i2p.util.Log;
* *
*/ */
public class Shitlist { public class Shitlist {
private final static Shitlist _instance = new Shitlist(); private Log _log;
public final static Shitlist getInstance() { return _instance; } private RouterContext _context;
private final static Log _log = new Log(Shitlist.class);
private Map _shitlist; // H(routerIdent) --> Date private Map _shitlist; // H(routerIdent) --> Date
public final static long SHITLIST_DURATION_MS = 4*60*1000; // 4 minute shitlist public final static long SHITLIST_DURATION_MS = 4*60*1000; // 4 minute shitlist
private Shitlist() { public Shitlist(RouterContext context) {
_context = context;
_log = context.logManager().getLog(Shitlist.class);
_shitlist = new HashMap(100); _shitlist = new HashMap(100);
} }
public boolean shitlistRouter(Hash peer) { public boolean shitlistRouter(Hash peer) {
if (peer == null) return false; if (peer == null) return false;
if (_context.routerHash().equals(peer)) {
_log.error("wtf, why did we try to shitlist ourselves?", new Exception("shitfaced"));
return false;
}
boolean wasAlready = false; boolean wasAlready = false;
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
_log.info("Shitlisting router " + peer.toBase64(), new Exception("Shitlist cause")); _log.info("Shitlisting router " + peer.toBase64(), new Exception("Shitlist cause"));
synchronized (_shitlist) { synchronized (_shitlist) {
Date oldDate = (Date)_shitlist.put(peer, new Date(Clock.getInstance().now())); Date oldDate = (Date)_shitlist.put(peer, new Date(_context.clock().now()));
wasAlready = (null == oldDate); wasAlready = (null == oldDate);
} }
NetworkDatabaseFacade.getInstance().fail(peer);
TunnelManagerFacade.getInstance().peerFailed(peer); _context.netDb().fail(peer);
_context.tunnelManager().peerFailed(peer);
return wasAlready; return wasAlready;
} }
@ -66,7 +72,7 @@ public class Shitlist {
if (shitlistDate == null) return false; if (shitlistDate == null) return false;
// check validity // check validity
if (shitlistDate.getTime() > Clock.getInstance().now() - SHITLIST_DURATION_MS) { if (shitlistDate.getTime() > _context.clock().now() - SHITLIST_DURATION_MS) {
return true; return true;
} else { } else {
unshitlistRouter(peer); unshitlistRouter(peer);
@ -83,7 +89,7 @@ public class Shitlist {
} }
buf.append("<ul>"); buf.append("<ul>");
long limit = Clock.getInstance().now() - SHITLIST_DURATION_MS; long limit = _context.clock().now() - SHITLIST_DURATION_MS;
for (Iterator iter = shitlist.keySet().iterator(); iter.hasNext(); ) { for (Iterator iter = shitlist.keySet().iterator(); iter.hasNext(); ) {
Hash key = (Hash)iter.next(); Hash key = (Hash)iter.next();

View File

@ -25,9 +25,8 @@ import net.i2p.util.Log;
* *
*/ */
public class StatisticsManager implements Service { public class StatisticsManager implements Service {
private final static Log _log = new Log(StatisticsManager.class); private Log _log;
private static StatisticsManager _instance = new StatisticsManager(); private RouterContext _context;
public static StatisticsManager getInstance() { return _instance; }
private boolean _includePeerRankings; private boolean _includePeerRankings;
private int _publishedStats; private int _publishedStats;
@ -36,13 +35,15 @@ public class StatisticsManager implements Service {
public final static String PROP_MAX_PUBLISHED_PEERS = "router.publishPeerMax"; public final static String PROP_MAX_PUBLISHED_PEERS = "router.publishPeerMax";
public final static int DEFAULT_MAX_PUBLISHED_PEERS = 20; public final static int DEFAULT_MAX_PUBLISHED_PEERS = 20;
public StatisticsManager() { public StatisticsManager(RouterContext context) {
_context = context;
_log = context.logManager().getLog(StatisticsManager.class);
_includePeerRankings = false; _includePeerRankings = false;
} }
public void shutdown() {} public void shutdown() {}
public void startup() { public void startup() {
String val = Router.getInstance().getConfigSetting(PROP_PUBLISH_RANKINGS); String val = _context.router().getConfigSetting(PROP_PUBLISH_RANKINGS);
try { try {
if (val == null) { if (val == null) {
if (_log.shouldLog(Log.INFO)) if (_log.shouldLog(Log.INFO))
@ -65,7 +66,7 @@ public class StatisticsManager implements Service {
+ "], so we're defaulting to FALSE"); + "], so we're defaulting to FALSE");
_includePeerRankings = false; _includePeerRankings = false;
} }
val = Router.getInstance().getConfigSetting(PROP_MAX_PUBLISHED_PEERS); val = _context.router().getConfigSetting(PROP_MAX_PUBLISHED_PEERS);
if (val == null) { if (val == null) {
_publishedStats = DEFAULT_MAX_PUBLISHED_PEERS; _publishedStats = DEFAULT_MAX_PUBLISHED_PEERS;
} else { } else {
@ -90,7 +91,7 @@ public class StatisticsManager implements Service {
stats.setProperty("core.id", CoreVersion.ID); stats.setProperty("core.id", CoreVersion.ID);
if (_includePeerRankings) { if (_includePeerRankings) {
stats.putAll(ProfileManager.getInstance().summarizePeers(_publishedStats)); stats.putAll(_context.profileManager().summarizePeers(_publishedStats));
includeRate("transport.sendProcessingTime", stats, new long[] { 60*1000, 60*60*1000 }); includeRate("transport.sendProcessingTime", stats, new long[] { 60*1000, 60*60*1000 });
//includeRate("tcp.queueSize", stats); //includeRate("tcp.queueSize", stats);
@ -110,7 +111,7 @@ public class StatisticsManager implements Service {
includeRate("netDb.successPeers", stats, new long[] { 60*60*1000 }); includeRate("netDb.successPeers", stats, new long[] { 60*60*1000 });
includeRate("transport.receiveMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("transport.receiveMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 });
includeRate("transport.sendMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 }); includeRate("transport.sendMessageSize", stats, new long[] { 5*60*1000, 60*60*1000 });
stats.setProperty("stat_uptime", DataHelper.formatDuration(Router.getInstance().getUptime())); stats.setProperty("stat_uptime", DataHelper.formatDuration(_context.router().getUptime()));
stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]"); stats.setProperty("stat__rateKey", "avg;maxAvg;pctLifetime;[sat;satLim;maxSat;maxSatLim;][num;lifetimeFreq;maxFreq]");
_log.debug("Publishing peer rankings"); _log.debug("Publishing peer rankings");
} else { } else {
@ -126,7 +127,7 @@ public class StatisticsManager implements Service {
includeRate(rateName, stats, null); includeRate(rateName, stats, null);
} }
private void includeRate(String rateName, Properties stats, long selectedPeriods[]) { private void includeRate(String rateName, Properties stats, long selectedPeriods[]) {
RateStat rate = StatManager.getInstance().getRate(rateName); RateStat rate = _context.statManager().getRate(rateName);
if (rate == null) return; if (rate == null) return;
long periods[] = rate.getPeriods(); long periods[] = rate.getPeriods();
for (int i = 0; i < periods.length; i++) { for (int i = 0; i < periods.length; i++) {

View File

@ -9,6 +9,7 @@ import net.i2p.util.Clock;
import net.i2p.util.HTTPSendData; import net.i2p.util.HTTPSendData;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.router.RouterContext;
/** /**
* Job that, if its allowed to, will submit the data gathered by the MessageHistory * Job that, if its allowed to, will submit the data gathered by the MessageHistory
@ -22,7 +23,7 @@ import net.i2p.util.Log;
* *
*/ */
public class SubmitMessageHistoryJob extends JobImpl { public class SubmitMessageHistoryJob extends JobImpl {
private final static Log _log = new Log(SubmitMessageHistoryJob.class); private Log _log;
/** default submitting data every hour */ /** default submitting data every hour */
private final static long DEFAULT_REQUEUE_DELAY = 60*60*1000; private final static long DEFAULT_REQUEUE_DELAY = 60*60*1000;
@ -38,6 +39,11 @@ public class SubmitMessageHistoryJob extends JobImpl {
/** default location */ /** default location */
public final static String DEFAULT_SUBMIT_URL = "http://i2p.net/cgi-bin/submitMessageHistory"; public final static String DEFAULT_SUBMIT_URL = "http://i2p.net/cgi-bin/submitMessageHistory";
public SubmitMessageHistoryJob(RouterContext context) {
super(context);
_log = context.logManager().getLog(SubmitMessageHistoryJob.class);
}
public void runJob() { public void runJob() {
if (shouldSubmit()) { if (shouldSubmit()) {
submit(); submit();
@ -56,13 +62,13 @@ public class SubmitMessageHistoryJob extends JobImpl {
I2PThread t = new I2PThread(new Runnable() { I2PThread t = new I2PThread(new Runnable() {
public void run() { public void run() {
_log.debug("Submitting data"); _log.debug("Submitting data");
MessageHistory.getInstance().setPauseFlushes(true); _context.messageHistory().setPauseFlushes(true);
String filename = MessageHistory.getInstance().getFilename(); String filename = _context.messageHistory().getFilename();
send(filename); send(filename);
MessageHistory.getInstance().setPauseFlushes(false); _context.messageHistory().setPauseFlushes(false);
Job job = new SubmitMessageHistoryJob(); Job job = new SubmitMessageHistoryJob(_context);
job.getTiming().setStartAfter(Clock.getInstance().now() + getRequeueDelay()); job.getTiming().setStartAfter(_context.clock().now() + getRequeueDelay());
JobQueue.getInstance().addJob(job); _context.jobQueue().addJob(job);
} }
}); });
t.setName("SubmitData"); t.setName("SubmitData");
@ -84,7 +90,7 @@ public class SubmitMessageHistoryJob extends JobImpl {
if (size > 0) if (size > 0)
expectedSend += (int)size/10; // compression expectedSend += (int)size/10; // compression
FileInputStream fin = new FileInputStream(dataFile); FileInputStream fin = new FileInputStream(dataFile);
BandwidthLimiter.getInstance().delayOutbound(null, expectedSend); _context.bandwidthLimiter().delayOutbound(null, expectedSend);
boolean sent = HTTPSendData.postData(url, size, fin); boolean sent = HTTPSendData.postData(url, size, fin);
fin.close(); fin.close();
boolean deleted = dataFile.delete(); boolean deleted = dataFile.delete();
@ -95,7 +101,7 @@ public class SubmitMessageHistoryJob extends JobImpl {
} }
private String getURL() { private String getURL() {
String str = Router.getInstance().getConfigSetting(PARAM_SUBMIT_URL); String str = _context.router().getConfigSetting(PARAM_SUBMIT_URL);
if ( (str == null) || (str.trim().length() <= 0) ) if ( (str == null) || (str.trim().length() <= 0) )
return DEFAULT_SUBMIT_URL; return DEFAULT_SUBMIT_URL;
else else
@ -103,7 +109,7 @@ public class SubmitMessageHistoryJob extends JobImpl {
} }
private boolean shouldSubmit() { private boolean shouldSubmit() {
String str = Router.getInstance().getConfigSetting(PARAM_SUBMIT_DATA); String str = _context.router().getConfigSetting(PARAM_SUBMIT_DATA);
if (str == null) { if (str == null) {
_log.debug("History submit config not specified [" + PARAM_SUBMIT_DATA + "], default = " + DEFAULT_SUBMIT_DATA); _log.debug("History submit config not specified [" + PARAM_SUBMIT_DATA + "], default = " + DEFAULT_SUBMIT_DATA);
return DEFAULT_SUBMIT_DATA; return DEFAULT_SUBMIT_DATA;

View File

@ -29,12 +29,13 @@ import net.i2p.data.i2np.TunnelConfigurationSessionKey;
import net.i2p.data.i2np.TunnelSessionKey; import net.i2p.data.i2np.TunnelSessionKey;
import net.i2p.data.i2np.TunnelSigningPrivateKey; import net.i2p.data.i2np.TunnelSigningPrivateKey;
import net.i2p.data.i2np.TunnelSigningPublicKey; import net.i2p.data.i2np.TunnelSigningPublicKey;
import net.i2p.util.Clock; import net.i2p.I2PAppContext;
/** /**
* Defines the information associated with a tunnel * Defines the information associated with a tunnel
*/ */
public class TunnelInfo extends DataStructureImpl { public class TunnelInfo extends DataStructureImpl {
private I2PAppContext _context;
private TunnelId _id; private TunnelId _id;
private Hash _nextHop; private Hash _nextHop;
private Hash _thisHop; private Hash _thisHop;
@ -50,7 +51,8 @@ public class TunnelInfo extends DataStructureImpl {
private boolean _ready; private boolean _ready;
private boolean _wasEverReady; private boolean _wasEverReady;
public TunnelInfo() { public TunnelInfo(I2PAppContext context) {
_context = context;
setTunnelId(null); setTunnelId(null);
setThisHop(null); setThisHop(null);
setNextHop(null); setNextHop(null);
@ -64,7 +66,7 @@ public class TunnelInfo extends DataStructureImpl {
_options = new Properties(); _options = new Properties();
_ready = false; _ready = false;
_wasEverReady = false; _wasEverReady = false;
_created = Clock.getInstance().now(); _created = _context.clock().now();
} }
public TunnelId getTunnelId() { return _id; } public TunnelId getTunnelId() { return _id; }
@ -179,7 +181,7 @@ public class TunnelInfo extends DataStructureImpl {
} }
Boolean includeNextInfo = DataHelper.readBoolean(in); Boolean includeNextInfo = DataHelper.readBoolean(in);
if (includeNextInfo.booleanValue()) { if (includeNextInfo.booleanValue()) {
_nextHopInfo = new TunnelInfo(); _nextHopInfo = new TunnelInfo(_context);
_nextHopInfo.readBytes(in); _nextHopInfo.readBytes(in);
} else { } else {
_nextHopInfo = null; _nextHopInfo = null;
@ -214,7 +216,7 @@ public class TunnelInfo extends DataStructureImpl {
} else { } else {
_verificationKey = null; _verificationKey = null;
} }
_settings = new TunnelSettings(); _settings = new TunnelSettings(_context);
_settings.readBytes(in); _settings.readBytes(in);
Boolean ready = DataHelper.readBoolean(in); Boolean ready = DataHelper.readBoolean(in);
if (ready != null) if (ready != null)

View File

@ -19,29 +19,27 @@ import net.i2p.router.tunnelmanager.PoolingTunnelManagerFacade;
* Build and maintain tunnels throughout the network. * Build and maintain tunnels throughout the network.
* *
*/ */
public abstract class TunnelManagerFacade implements Service { public interface TunnelManagerFacade extends Service {
private static TunnelManagerFacade _instance = new PoolingTunnelManagerFacade();
public static TunnelManagerFacade getInstance() { return _instance; }
/** /**
* React to a request to join the specified tunnel. * React to a request to join the specified tunnel.
* *
* @return true if the router will accept participation, else false. * @return true if the router will accept participation, else false.
*/ */
public abstract boolean joinTunnel(TunnelInfo info); boolean joinTunnel(TunnelInfo info);
/** /**
* Retrieve the information related to a particular tunnel * Retrieve the information related to a particular tunnel
* *
*/ */
public abstract TunnelInfo getTunnelInfo(TunnelId id); TunnelInfo getTunnelInfo(TunnelId id);
/** /**
* Retrieve a set of tunnels from the existing ones for various purposes * Retrieve a set of tunnels from the existing ones for various purposes
*/ */
public abstract List selectOutboundTunnelIds(TunnelSelectionCriteria criteria); List selectOutboundTunnelIds(TunnelSelectionCriteria criteria);
/** /**
* Retrieve a set of tunnels from the existing ones for various purposes * Retrieve a set of tunnels from the existing ones for various purposes
*/ */
public abstract List selectInboundTunnelIds(TunnelSelectionCriteria criteria); List selectInboundTunnelIds(TunnelSelectionCriteria criteria);
/** /**
* Make sure appropriate outbound tunnels are in place, builds requested * Make sure appropriate outbound tunnels are in place, builds requested
@ -49,18 +47,18 @@ public abstract class TunnelManagerFacade implements Service {
* validate the leaseSet, then publish it in the network database. * validate the leaseSet, then publish it in the network database.
* *
*/ */
public abstract void createTunnels(Destination destination, ClientTunnelSettings clientSettings, long timeoutMs); void createTunnels(Destination destination, ClientTunnelSettings clientSettings, long timeoutMs);
/** /**
* Called when a peer becomes unreachable - go through all of the current * Called when a peer becomes unreachable - go through all of the current
* tunnels and rebuild them if we can, or drop them if we can't. * tunnels and rebuild them if we can, or drop them if we can't.
* *
*/ */
public abstract void peerFailed(Hash peer); void peerFailed(Hash peer);
/** /**
* True if the peer currently part of a tunnel * True if the peer currently part of a tunnel
* *
*/ */
public abstract boolean isInUse(Hash peer); boolean isInUse(Hash peer);
} }

View File

@ -16,13 +16,14 @@ import java.util.Date;
import net.i2p.data.DataFormatException; import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.data.DataStructureImpl; import net.i2p.data.DataStructureImpl;
import net.i2p.util.Clock; import net.i2p.I2PAppContext;
/** /**
* Wrap up the settings specified for a particular tunnel * Wrap up the settings specified for a particular tunnel
* *
*/ */
public class TunnelSettings extends DataStructureImpl { public class TunnelSettings extends DataStructureImpl {
private I2PAppContext _context;
private int _depth; private int _depth;
private long _msgsPerMinuteAvg; private long _msgsPerMinuteAvg;
private long _bytesPerMinuteAvg; private long _bytesPerMinuteAvg;
@ -33,7 +34,8 @@ public class TunnelSettings extends DataStructureImpl {
private long _expiration; private long _expiration;
private long _created; private long _created;
public TunnelSettings() { public TunnelSettings(I2PAppContext context) {
_context = context;
_depth = 0; _depth = 0;
_msgsPerMinuteAvg = 0; _msgsPerMinuteAvg = 0;
_msgsPerMinutePeak = 0; _msgsPerMinutePeak = 0;
@ -42,7 +44,7 @@ public class TunnelSettings extends DataStructureImpl {
_includeDummy = false; _includeDummy = false;
_reorder = false; _reorder = false;
_expiration = 0; _expiration = 0;
_created = Clock.getInstance().now(); _created = _context.clock().now();
} }
public int getDepth() { return _depth; } public int getDepth() { return _depth; }
@ -84,7 +86,7 @@ public class TunnelSettings extends DataStructureImpl {
if (created != null) if (created != null)
_created = created.getTime(); _created = created.getTime();
else else
_created = Clock.getInstance().now(); _created = _context.clock().now();
} }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { public void writeBytes(OutputStream out) throws DataFormatException, IOException {

View File

@ -14,6 +14,7 @@ import java.net.Socket;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.router.RouterContext;
/** /**
* Listen for connections on the specified port, and toss them onto the client manager's * Listen for connections on the specified port, and toss them onto the client manager's
@ -22,13 +23,16 @@ import net.i2p.util.Log;
* @author jrandom * @author jrandom
*/ */
public class AdminListener implements Runnable { public class AdminListener implements Runnable {
private final static Log _log = new Log(AdminListener.class); private Log _log;
private RouterContext _context;
private ServerSocket _socket; private ServerSocket _socket;
private int _port; private int _port;
private boolean _running; private boolean _running;
private long _nextFailDelay = 1000; private long _nextFailDelay = 1000;
public AdminListener(int port) { public AdminListener(RouterContext context, int port) {
_context = context;
_log = context.logManager().getLog(AdminListener.class);
_port = port; _port = port;
_running = false; _running = false;
} }
@ -90,7 +94,7 @@ public class AdminListener implements Runnable {
* *
*/ */
protected void runConnection(Socket socket) throws IOException { protected void runConnection(Socket socket) throws IOException {
AdminRunner runner = new AdminRunner(socket); AdminRunner runner = new AdminRunner(_context, socket);
I2PThread t = new I2PThread(runner); I2PThread t = new I2PThread(runner);
t.setName("Admin Runner"); t.setName("Admin Runner");
t.setPriority(Thread.MIN_PRIORITY); t.setPriority(Thread.MIN_PRIORITY);

View File

@ -4,16 +4,21 @@ import net.i2p.router.Router;
import net.i2p.router.Service; import net.i2p.router.Service;
import net.i2p.util.I2PThread; import net.i2p.util.I2PThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.router.RouterContext;
public class AdminManager implements Service { public class AdminManager implements Service {
private final static Log _log = new Log(AdminManager.class); private Log _log;
private final static AdminManager _instance = new AdminManager(); private RouterContext _context;
public final static AdminManager getInstance() { return _instance; }
public final static String PARAM_ADMIN_PORT = "router.adminPort"; public final static String PARAM_ADMIN_PORT = "router.adminPort";
public final static int DEFAULT_ADMIN_PORT = 7655; public final static int DEFAULT_ADMIN_PORT = 7655;
private AdminListener _listener; private AdminListener _listener;
public AdminManager(RouterContext context) {
_context = context;
_log = context.logManager().getLog(AdminManager.class);
}
public String renderStatusHTML() { return ""; } public String renderStatusHTML() { return ""; }
public void shutdown() { public void shutdown() {
@ -26,7 +31,7 @@ public class AdminManager implements Service {
public void startup() { public void startup() {
int port = DEFAULT_ADMIN_PORT; int port = DEFAULT_ADMIN_PORT;
String str = Router.getInstance().getConfigSetting(PARAM_ADMIN_PORT); String str = _context.router().getConfigSetting(PARAM_ADMIN_PORT);
if (str != null) { if (str != null) {
try { try {
int val = Integer.parseInt(str); int val = Integer.parseInt(str);
@ -40,7 +45,7 @@ public class AdminManager implements Service {
} }
private void startup(int port) { private void startup(int port) {
_listener = new AdminListener(port); _listener = new AdminListener(_context, port);
I2PThread t = new I2PThread(_listener); I2PThread t = new I2PThread(_listener);
t.setName("Admin Listener"); t.setName("Admin Listener");
t.setDaemon(true); t.setDaemon(true);

Some files were not shown because too many files have changed in this diff Show More