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);
@ -31,7 +33,7 @@ public class ProxyHandler extends EepHandler {
* @throws IOException * @throws IOException
*/ */
public void handle(Request req, HTTPListener httpl, OutputStream out public void handle(Request req, HTTPListener httpl, OutputStream out
/*, boolean fromProxy */) throws IOException { /*, boolean fromProxy */) throws IOException {
SocketManagerProducer smp = httpl.getSMP(); SocketManagerProducer smp = httpl.getSMP();
Destination dest = findProxy(); Destination dest = findProxy();
if (dest == null) { if (dest == null) {
@ -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,7 +42,12 @@ 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
* a new session. * a new session.
@ -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 */
@ -79,6 +80,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected I2CPMessageProducer _producer; protected I2CPMessageProducer _producer;
/** 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;
@ -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);
@ -139,13 +148,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
_portNum = Integer.parseInt(portNum); _portNum = Integer.parseInt(portNum);
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Invalid port number specified, defaulting to " _log.warn("Invalid port number specified, defaulting to "
+ TestServer.LISTEN_PORT, nfe); + TestServer.LISTEN_PORT, nfe);
_portNum = TestServer.LISTEN_PORT; _portNum = TestServer.LISTEN_PORT;
} }
} }
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);
} catch (Exception ex) { Constructor con = cls.getConstructor(new Class[] { I2PAppContext.class });
_log.error("Cannot loadNaming service implementation", ex); instance = (NamingService)con.newInstance(new Object[] { context });
instance = new DummyNamingService(); // fallback } catch (Exception ex) {
} _log.error("Cannot loadNaming service implementation", ex);
instance = new DummyNamingService(context); // fallback
} }
return instance; return instance;
} }

View File

@ -19,26 +19,20 @@ 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
* @param payload data to be encrypted * @param payload data to be encrypted
* @param sessionKey private esession key to encrypt to * @param sessionKey private esession key to encrypt to
@ -59,13 +53,13 @@ public class AESEngine {
if ((iv == null) || (payload == null) || (sessionKey == null) || (iv.length != 16)) return null; 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,10 +24,15 @@ 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)
@ -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 static DSAEngine getInstance() { public DSAEngine(I2PAppContext context) {
return _instance; _log = context.logManager().getLog(DSAEngine.class);
_context = context;
} }
public static DSAEngine getInstance() {
return I2PAppContext.getGlobalContext().dsa();
}
public boolean verifySignature(Signature signature, byte signedData[], SigningPublicKey verifyingKey) { 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,11 +27,19 @@ 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
* @param publicKey public key encrypt to * @param publicKey public key encrypt to

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,28 +38,27 @@ 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;
"how frequently we encrypt to a new ElGamal/AES+SessionTag session?",
"Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptNewSession",
StatManager.getInstance() "how frequently we encrypt to a new ElGamal/AES+SessionTag session?",
.createFrequencyStat("crypto.elGamalAES.encryptExistingSession", "Encryption", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l});
"how frequently we encrypt to an existing ElGamal/AES+SessionTag session?", _context.statManager().createFrequencyStat("crypto.elGamalAES.encryptExistingSession",
"Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l}); "how frequently we encrypt to an existing ElGamal/AES+SessionTag session?",
StatManager.getInstance() "Encryption", new long[] { 60 * 1000l, 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
.createFrequencyStat("crypto.elGamalAES.decryptNewSession", _context.statManager().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}); _context.statManager().createFrequencyStat("crypto.elGamalAES.decryptFail",
StatManager.getInstance() "how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption",
.createFrequencyStat("crypto.elGamalAES.decryptFail", new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
"how frequently we fail to decrypt with ElGamal/AES+SessionTag?", "Encryption",
new long[] { 60 * 60 * 1000l, 24 * 60 * 60 * 1000l});
} }
/** /**
@ -66,7 +66,7 @@ public class ElGamalAESEngine {
* ElGamal+AES algorithm in the data structure spec. * 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(); * The ElGamal engine should only be constructed and accessed through the
else * application context. This constructor should only be used by the
_engine = new ElGamalEngine(); * appropriate application context itself.
*
StatManager.getInstance().createRateStat("crypto.elGamal.encrypt", */
"how long does it take to do a full ElGamal encryption", "Encryption", public ElGamalEngine(I2PAppContext context) {
new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000}); context.statManager().createRateStat("crypto.elGamal.encrypt",
StatManager.getInstance().createRateStat("crypto.elGamal.decrypt", "how long does it take to do a full ElGamal encryption", "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.statManager().createRateStat("crypto.elGamal.decrypt",
"how long does it take to do a full ElGamal decryption", "Encryption",
new long[] { 60 * 1000, 60 * 60 * 1000, 24 * 60 * 60 * 1000});
_context = context;
_log = context.logManager().getLog(ElGamalEngine.class);
} }
private ElGamalEngine() {}
public static ElGamalEngine getInstance() {
return _engine;
}
private final static BigInteger _two = new NativeBigInteger(1, new byte[] { 0x02}); private 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,12 +24,11 @@ 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,
* or null if a new session key should be generated. * or null if a new session key should be generated.

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,24 +65,18 @@ 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))) { break;
_log.debug("Failed eqtest [" + new String(eqBuf) + "]");
break;
}
String val = readString(in);
read = read(in, semiBuf);
if ((read != semiBuf.length) || (!eq(new String(semiBuf), _semicolon))) {
_log.debug("Failed semitest [" + new String(semiBuf) + "]");
break;
}
props.put(key, val);
} }
} catch (IOException ioe) { String val = readString(in);
_log.warn("Error reading properties", ioe); read = read(in, semiBuf);
if ((read != semiBuf.length) || (!eq(new String(semiBuf), _semicolon))) {
break;
}
props.put(key, val);
} }
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,33 +70,46 @@ 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) {
@ -145,5 +166,32 @@ public class Log {
else else
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;
@ -83,7 +82,59 @@ 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;
} }
@ -123,18 +174,7 @@ public class LogManager {
_records.add(record); _records.add(record);
} }
} }
/**
* Called during Log construction
*
*/
void registerLog(Log log) {
synchronized (_logs) {
_logs.add(log);
}
updateLimit(log);
}
/** /**
* Called periodically by the log writer's thread * 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,10 +347,13 @@ 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) {
@ -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,8 +29,14 @@ 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

@ -1,138 +1,140 @@
package net.i2p.crypto; package net.i2p.crypto;
/* /*
* Copyright (c) 2003, TheCrypto * Copyright (c) 2003, TheCrypto
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, this * - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. * list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, * - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * and/or other materials provided with the distribution.
* - Neither the name of the TheCrypto may be used to endorse or promote * - Neither the name of the TheCrypto may be used to endorse or promote
* products derived from this software without specific prior written * products derived from this software without specific prior written
* permission. * permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
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 = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
}; };
byte[] plain = new byte[cplain.length]; byte[] plain = new byte[cplain.length];
for (int x = 0; x < cplain.length; x++) { for (int x = 0; x < cplain.length; x++) {
plain[x] = (byte)cplain[x]; plain[x] = (byte)cplain[x];
} }
char[] ckey = { char[] ckey = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
}; };
byte[] bkey = new byte[ckey.length]; byte[] bkey = new byte[ckey.length];
for (int x = 0; x < ckey.length; x++) { for (int x = 0; x < ckey.length; x++) {
bkey[x] = (byte)ckey[x]; bkey[x] = (byte)ckey[x];
} }
SessionKey key = new SessionKey(); SessionKey key = new SessionKey();
key.setData(bkey); key.setData(bkey);
char[] civ = { char[] civ = {
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0xfe, 0xdc, 0xba, 0x98, 0x67, 0x54, 0x32, 0x10 0xfe, 0xdc, 0xba, 0x98, 0x67, 0x54, 0x32, 0x10
}; };
byte[] iv = new byte[civ.length]; byte[] iv = new byte[civ.length];
for (int x = 0; x < iv.length; x++) { for (int x = 0; x < iv.length; x++) {
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]) {
same = false; same = false;
} }
} }
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);
System.out.println(); System.out.println();
System.out.println(); System.out.println();
long times = 100; long times = 100;
long encrypttime = 0; long encrypttime = 0;
long decrypttime = 0; long decrypttime = 0;
long maxE = 0; long maxE = 0;
long minE = 0; long minE = 0;
long maxD = 0; long maxD = 0;
long minD = 0; long minD = 0;
byte[] message = new byte[2*1024]; byte[] message = new byte[2*1024];
for (int i = 0; i < message.length; i++) for (int i = 0; i < message.length; i++)
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;
decrypttime += enddecrypt - endencryptstartdecrypt; decrypttime += enddecrypt - endencryptstartdecrypt;
if (!DataHelper.eq(d, message)) { if (!DataHelper.eq(d, message)) {
System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]"); System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]");
System.out.println("Data: dest [" + DataHelper.toString(d, d.length) + "]"); System.out.println("Data: dest [" + DataHelper.toString(d, d.length) + "]");
throw new RuntimeException("Holy crap, decrypted != source message"); throw new RuntimeException("Holy crap, decrypted != source message");
} }
if ( (minE == 0) && (minD == 0) ) { if ( (minE == 0) && (minD == 0) ) {
minE = endencryptstartdecrypt - startencrypt; minE = endencryptstartdecrypt - startencrypt;
maxE = endencryptstartdecrypt - startencrypt; maxE = endencryptstartdecrypt - startencrypt;
minD = enddecrypt - endencryptstartdecrypt; minD = enddecrypt - endencryptstartdecrypt;
maxD = enddecrypt - endencryptstartdecrypt; maxD = enddecrypt - endencryptstartdecrypt;
} else { } else {
if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt; if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt;
if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt; if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt;
if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt; if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt;
if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt; if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt;
} }
} }
System.out.println(); System.out.println();
System.out.println("Data size : " + message.length); System.out.println("Data size : " + message.length);
System.out.println("Encryption Time Average : " + (encrypttime/times) + "ms\ttotal: " + encrypttime + "ms\tmin: " + minE + "ms\tmax: " + maxE + "ms\tEncryption Bps: " + (times*message.length*1000)/encrypttime); System.out.println("Encryption Time Average : " + (encrypttime/times) + "ms\ttotal: " + encrypttime + "ms\tmin: " + minE + "ms\tmax: " + maxE + "ms\tEncryption Bps: " + (times*message.length*1000)/encrypttime);
System.out.println("Decryption Time Average : " + (decrypttime/times) + "ms\ttotal: " + decrypttime + "ms\tmin: " + minD + "ms\tmax: " + maxD + "ms\tDecryption Bps: " + (times*message.length*1000)/decrypttime); System.out.println("Decryption Time Average : " + (decrypttime/times) + "ms\ttotal: " + decrypttime + "ms\tmin: " + minD + "ms\tmax: " + maxD + "ms\tDecryption Bps: " + (times*message.length*1000)/decrypttime);
} }
} }

View File

@ -1,13 +1,14 @@
package net.i2p.crypto; package net.i2p.crypto;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
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,211 +26,216 @@ 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);
public void runRoundtripTest() { private I2PAppContext _context;
try { public ElGamalAESEngineTest(I2PAppContext ctx) {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair(); _context = ctx;
PublicKey pubKey = (PublicKey)keys[0];
PrivateKey privKey = (PrivateKey)keys[1];
String msg = "Hello world";
Set toBeDelivered = new HashSet();
SessionKey key = SessionKeyManager.getInstance().getCurrentKey(pubKey);
if (key == null)
key = SessionKeyManager.getInstance().createSession(pubKey);
byte[] encrypted = ElGamalAESEngine.encrypt(msg.getBytes(), pubKey, key, 64);
byte[] decrypted = ElGamalAESEngine.decrypt(encrypted, privKey);
if (decrypted == null)
throw new Exception("Failed to decrypt");
String read = new String(decrypted);
_log.debug("read: " + read);
_log.debug("Match? " + msg.equals(read));
} catch (Exception e) {
_log.error("Error", e);
try { Thread.sleep(5000); } catch (InterruptedException ie) {}
System.exit(0);
}
} }
public void runRoundtripTest() {
try {
Object keys[] = KeyGenerator.getInstance().generatePKIKeypair();
PublicKey pubKey = (PublicKey)keys[0];
PrivateKey privKey = (PrivateKey)keys[1];
String msg = "Hello world";
Set toBeDelivered = new HashSet();
SessionKey key = _context.sessionKeyManager().getCurrentKey(pubKey);
if (key == null)
key = _context.sessionKeyManager().createSession(pubKey);
byte[] encrypted = _context.elGamalAESEngine().encrypt(msg.getBytes(), pubKey, key, 64);
byte[] decrypted = _context.elGamalAESEngine().decrypt(encrypted, privKey);
if (decrypted == null)
throw new Exception("Failed to decrypt");
String read = new String(decrypted);
_log.debug("read: " + read);
_log.debug("Match? " + msg.equals(read));
} catch (Exception e) {
_log.error("Error", e);
try { Thread.sleep(5000); } catch (InterruptedException ie) {}
System.exit(0);
}
}
public void runLoopTest(int runs) { public void runLoopTest(int runs) {
try { try {
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];
long e0 = 0; long e0 = 0;
long d0 = 0; long d0 = 0;
long eTot = 0; long eTot = 0;
long dTot = 0; long dTot = 0;
for (int i = 0; i < runs; i++) { for (int i = 0; i < runs; i++) {
long times[] = runMessage(pubKey, privKey); long times[] = runMessage(pubKey, privKey);
_log.debug("E[" + i + "] time: " + times[0] + "ms"); _log.debug("E[" + i + "] time: " + times[0] + "ms");
_log.debug("D["+i+"] time: " + times[1] + "ms"); _log.debug("D["+i+"] time: " + times[1] + "ms");
if (i == 0) { if (i == 0) {
e0 = times[0]; e0 = times[0];
d0 = times[1]; d0 = times[1];
} }
eTot += times[0]; eTot += times[0];
dTot += times[1]; dTot += times[1];
} }
_log.debug("E average time: " + eTot/runs + "ms"); _log.debug("E average time: " + eTot/runs + "ms");
_log.debug("D average time: " + dTot/runs + "ms"); _log.debug("D average time: " + dTot/runs + "ms");
_log.debug("Total time to send and receive " + (runs) + "Kb: " + (eTot+dTot)+"ms"); _log.debug("Total time to send and receive " + (runs) + "Kb: " + (eTot+dTot)+"ms");
} catch (Exception e) { } catch (Exception e) {
_log.error("Error", e); _log.error("Error", e);
try { Thread.sleep(5000); } catch (InterruptedException ie) {} try { Thread.sleep(5000); } catch (InterruptedException ie) {}
System.exit(0); System.exit(0);
} }
} }
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");
return null; return null;
} }
long rv[] = new long[2]; long rv[] = new long[2];
rv[0] = afterE - beforeE; rv[0] = afterE - beforeE;
rv[1] = afterD - afterE; rv[1] = afterD - afterE;
return rv; return rv;
} }
public void runAESTest() { public void runAESTest() {
try { try {
SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey(); SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey();
Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData());
byte iv[] = new byte[16]; byte iv[] = new byte[16];
System.arraycopy(h.getData(), 0, iv, 0, 16); System.arraycopy(h.getData(), 0, iv, 0, 16);
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);
_log.debug("Match? " + msg.equals(read)); _log.debug("Match? " + msg.equals(read));
} catch (Exception e) { } catch (Exception e) {
_log.error("Error", e); _log.error("Error", e);
try { Thread.sleep(5000); } catch (InterruptedException ie) {} try { Thread.sleep(5000); } catch (InterruptedException ie) {}
System.exit(0); System.exit(0);
} }
} }
public void runBasicAESTest() { public void runBasicAESTest() {
try { try {
SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey(); SessionKey sessionKey = KeyGenerator.getInstance().generateSessionKey();
Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData()); Hash h = SHA256Generator.getInstance().calculateHash(sessionKey.getData());
byte iv[] = new byte[16]; byte iv[] = new byte[16];
System.arraycopy(h.getData(), 0, iv, 0, 16); System.arraycopy(h.getData(), 0, iv, 0, 16);
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))) {
_log.debug("**AES Basic test passed!\n\n"); _log.debug("**AES Basic test passed!\n\n");
} }
} catch (Exception e) { } catch (Exception e) {
_log.error("Error", e); _log.error("Error", e);
try { Thread.sleep(5000); } catch (InterruptedException ie) {} try { Thread.sleep(5000); } catch (InterruptedException ie) {}
System.exit(0); System.exit(0);
} }
} }
public void runElGamalTest(int numLoops) { public void runElGamalTest(int numLoops) {
for (int i = 0; i < numLoops; i++) { for (int i = 0; i < numLoops; i++) {
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 key = KeyGenerator.getInstance().generateSessionKey(); SessionKey key = KeyGenerator.getInstance().generateSessionKey();
runBasicElGamalTest(key, pubKey, privKey); runBasicElGamalTest(key, pubKey, privKey);
} }
} }
public void runBasicElGamalTest(SessionKey key, PublicKey pubKey, PrivateKey privKey) { public void runBasicElGamalTest(SessionKey key, PublicKey pubKey, PrivateKey privKey) {
try { try {
ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(256); ByteArrayOutputStream elgSrc = new ByteArrayOutputStream(256);
key.writeBytes(elgSrc); key.writeBytes(elgSrc);
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();
nk.readBytes(bais); nk.readBytes(bais);
byte postpreIV[] = new byte[32]; byte postpreIV[] = new byte[32];
int read = bais.read(postpreIV); int read = bais.read(postpreIV);
if (read != postpreIV.length) { if (read != postpreIV.length) {
// hmm, this can't really happen... // hmm, this can't really happen...
throw new Exception("Somehow ElGamal broke and 256 bytes is less than 32 bytes..."); throw new Exception("Somehow ElGamal broke and 256 bytes is less than 32 bytes...");
} }
// ignore the next 192 bytes // ignore the next 192 bytes
boolean eq = (DataHelper.eq(preIV, postpreIV) && DataHelper.eq(key, nk)); boolean eq = (DataHelper.eq(preIV, postpreIV) && DataHelper.eq(key, nk));
if (!eq) { if (!eq) {
_log.error("elgEncr.length: " + elgEncr.length + " elgDecr.length: " + elgDecr.length); _log.error("elgEncr.length: " + elgEncr.length + " elgDecr.length: " + elgDecr.length);
_log.error("Pre IV.................: " + DataHelper.toString(preIV, 32)); _log.error("Pre IV.................: " + DataHelper.toString(preIV, 32));
_log.error("Pre IV after decryption: " + DataHelper.toString(postpreIV, 32)); _log.error("Pre IV after decryption: " + DataHelper.toString(postpreIV, 32));
_log.error("SessionKey.................: " + DataHelper.toString(key.getData(), 32)); _log.error("SessionKey.................: " + DataHelper.toString(key.getData(), 32));
_log.error("SessionKey after decryption: " + DataHelper.toString(nk.getData(), 32)); _log.error("SessionKey after decryption: " + DataHelper.toString(nk.getData(), 32));
_log.error("PublicKey: " + DataHelper.toDecimalString(pubKey.getData(), pubKey.getData().length)); _log.error("PublicKey: " + DataHelper.toDecimalString(pubKey.getData(), pubKey.getData().length));
_log.error("PrivateKey: " + DataHelper.toDecimalString(privKey.getData(), privKey.getData().length)); _log.error("PrivateKey: " + DataHelper.toDecimalString(privKey.getData(), privKey.getData().length));
throw new Exception("Not equal!"); throw new Exception("Not equal!");
} else { } else {
_log.debug("Basic ElG D(E(val)) == val"); _log.debug("Basic ElG D(E(val)) == val");
} }
} catch (Exception e) { } catch (Exception e) {
_log.error("Error", e); _log.error("Error", e);
try { Thread.sleep(5000); } catch (InterruptedException ie) {} try { Thread.sleep(5000); } catch (InterruptedException ie) {}
System.exit(0); System.exit(0);
} }
} }
public static void main(String args[]) { public static void main(String args[]) {
ElGamalAESEngineTest tst = new ElGamalAESEngineTest(); I2PAppContext context = new I2PAppContext();
Object o = YKGenerator.class; ElGamalAESEngineTest tst = new ElGamalAESEngineTest(context);
try { Thread.sleep(120*1000); } catch (InterruptedException ie) {} Object o = YKGenerator.class;
try { Thread.sleep(120*1000); } catch (InterruptedException ie) {}
tst.runBasicAESTest();
tst.runAESTest(); tst.runBasicAESTest();
tst.runRoundtripTest(); tst.runAESTest();
tst.runElGamalTest(2); tst.runRoundtripTest();
// test bug tst.runElGamalTest(2);
for (int i = 0; i < 3; i++) // test bug
tst.runLoopTest(1); for (int i = 0; i < 3; i++)
// test throughput tst.runLoopTest(1);
tst.runLoopTest(5); // test throughput
tst.runLoopTest(5);
net.i2p.stat.SimpleStatDumper.dumpStats(Log.CRIT);
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {} net.i2p.stat.SimpleStatDumper.dumpStats(context, Log.CRIT);
try { Thread.sleep(5*1000); } catch (InterruptedException ie) {}
} }
} }

View File

@ -1,96 +1,98 @@
package net.i2p.crypto; package net.i2p.crypto;
/* /*
* Copyright (c) 2003, TheCrypto * Copyright (c) 2003, TheCrypto
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* *
* - Redistributions of source code must retain the above copyright notice, this * - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. * list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice, * - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation * this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution. * and/or other materials provided with the distribution.
* - Neither the name of the TheCrypto may be used to endorse or promote * - Neither the name of the TheCrypto may be used to endorse or promote
* products derived from this software without specific prior written * products derived from this software without specific prior written
* permission. * permission.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
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 {
public static void main(String args[]) { private static I2PAppContext _context = new I2PAppContext();
int times = 100; public static void main(String args[]) {
long keygentime = 0; int times = 100;
long encrypttime = 0; long keygentime = 0;
long decrypttime = 0; long encrypttime = 0;
long maxKey = 0; long decrypttime = 0;
long minKey = 0; long maxKey = 0;
long maxE = 0; long minKey = 0;
long minE = 0; long maxE = 0;
long maxD = 0; long minE = 0;
long minD = 0; long maxD = 0;
Object[] keys = KeyGenerator.getInstance().generatePKIKeypair(); long minD = 0;
byte[] message = new byte[222]; Object[] keys = KeyGenerator.getInstance().generatePKIKeypair();
for (int i = 0; i < message.length; i++) byte[] message = new byte[222];
message[i] = (byte)((i%26)+'a'); for (int i = 0; i < message.length; i++)
for (int x = 0; x < times; x++) { message[i] = (byte)((i%26)+'a');
long startkeys = System.currentTimeMillis(); for (int x = 0; x < times; x++) {
keys = KeyGenerator.getInstance().generatePKIKeypair(); long startkeys = System.currentTimeMillis();
PublicKey pubkey = (PublicKey)keys[0]; keys = KeyGenerator.getInstance().generatePKIKeypair();
PrivateKey privkey = (PrivateKey)keys[1]; PublicKey pubkey = (PublicKey)keys[0];
long endkeys = System.currentTimeMillis(); PrivateKey privkey = (PrivateKey)keys[1];
long startencrypt = System.currentTimeMillis(); long endkeys = System.currentTimeMillis();
byte[] e = ElGamalEngine.getInstance().encrypt(message, pubkey); long startencrypt = System.currentTimeMillis();
long endencryptstartdecrypt = System.currentTimeMillis(); byte[] e = _context.elGamalEngine().encrypt(message, pubkey);
byte[] d = ElGamalEngine.getInstance().decrypt(e, privkey); long endencryptstartdecrypt = System.currentTimeMillis();
long enddecrypt = System.currentTimeMillis(); byte[] d = _context.elGamalEngine().decrypt(e, privkey);
System.out.print("."); long enddecrypt = System.currentTimeMillis();
keygentime += endkeys - startkeys; System.out.print(".");
encrypttime += endencryptstartdecrypt - startencrypt; keygentime += endkeys - startkeys;
decrypttime += enddecrypt - endencryptstartdecrypt; encrypttime += endencryptstartdecrypt - startencrypt;
if (!DataHelper.eq(d, message)) { decrypttime += enddecrypt - endencryptstartdecrypt;
System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]"); if (!DataHelper.eq(d, message)) {
byte hash1[] = SHA256Generator.getInstance().calculateHash(message).getData(); System.out.println("Lengths: source [" + message.length + "] dest [" + d.length + "]");
byte hash2[] = SHA256Generator.getInstance().calculateHash(d).getData(); byte hash1[] = SHA256Generator.getInstance().calculateHash(message).getData();
System.out.println("Hashes: source [" + DataHelper.toString(hash1, hash1.length) + "] dest [" + DataHelper.toString(hash2, hash2.length) + "]"); byte hash2[] = SHA256Generator.getInstance().calculateHash(d).getData();
throw new RuntimeException("Holy crap, decrypted != source message"); System.out.println("Hashes: source [" + DataHelper.toString(hash1, hash1.length) + "] dest [" + DataHelper.toString(hash2, hash2.length) + "]");
} throw new RuntimeException("Holy crap, decrypted != source message");
if ( (minKey == 0) && (minE == 0) && (minD == 0) ) { }
minKey = endkeys - startkeys; if ( (minKey == 0) && (minE == 0) && (minD == 0) ) {
maxKey = endkeys - startkeys; minKey = endkeys - startkeys;
minE = endencryptstartdecrypt - startencrypt; maxKey = endkeys - startkeys;
maxE = endencryptstartdecrypt - startencrypt; minE = endencryptstartdecrypt - startencrypt;
minD = enddecrypt - endencryptstartdecrypt; maxE = endencryptstartdecrypt - startencrypt;
maxD = enddecrypt - endencryptstartdecrypt; minD = enddecrypt - endencryptstartdecrypt;
} else { maxD = enddecrypt - endencryptstartdecrypt;
if (minKey > endkeys - startkeys) minKey = endkeys - startkeys; } else {
if (maxKey < endkeys - startkeys) maxKey = endkeys - startkeys; if (minKey > endkeys - startkeys) minKey = endkeys - startkeys;
if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt; if (maxKey < endkeys - startkeys) maxKey = endkeys - startkeys;
if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt; if (minE > endencryptstartdecrypt - startencrypt) minE = endencryptstartdecrypt - startencrypt;
if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt; if (maxE < endencryptstartdecrypt - startencrypt) maxE = endencryptstartdecrypt - startencrypt;
if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt; if (minD > enddecrypt - endencryptstartdecrypt) minD = enddecrypt - endencryptstartdecrypt;
} if (maxD < enddecrypt - endencryptstartdecrypt) maxD = enddecrypt - endencryptstartdecrypt;
} }
System.out.println(); }
System.out.println("Key Generation Time Average: " + (keygentime/times) + "\ttotal: " + keygentime + "\tmin: " + minKey + "\tmax: " + maxKey + "\tKeygen/second: " + (keygentime == 0 ? "NaN" : ""+(times*1000)/keygentime)); System.out.println();
System.out.println("Encryption Time Average : " + (encrypttime/times) + "\ttotal: " + encrypttime + "\tmin: " + minE + "\tmax: " + maxE + "\tEncryption Bps: " + (times*message.length*1000)/encrypttime); System.out.println("Key Generation Time Average: " + (keygentime/times) + "\ttotal: " + keygentime + "\tmin: " + minKey + "\tmax: " + maxKey + "\tKeygen/second: " + (keygentime == 0 ? "NaN" : ""+(times*1000)/keygentime));
System.out.println("Decryption Time Average : " + (decrypttime/times) + "\ttotal: " + decrypttime + "\tmin: " + minD + "\tmax: " + maxD + "\tDecryption Bps: " + (times*message.length*1000)/decrypttime); System.out.println("Encryption Time Average : " + (encrypttime/times) + "\ttotal: " + encrypttime + "\tmin: " + minE + "\tmax: " + maxE + "\tEncryption Bps: " + (times*message.length*1000)/encrypttime);
} System.out.println("Decryption Time Average : " + (decrypttime/times) + "\ttotal: " + decrypttime + "\tmin: " + minD + "\tmax: " + maxD + "\tDecryption Bps: " + (times*message.length*1000)/decrypttime);
}
} }

View File

@ -1,9 +1,9 @@
package net.i2p.crypto; package net.i2p.crypto;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -16,6 +16,7 @@ import net.i2p.data.DataHelper;
import net.i2p.util.Log; import net.i2p.util.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;
@ -24,383 +25,384 @@ import java.util.Set;
* *
* session key management unit tests: * session key management unit tests:
* *
* Run tagsIncluded useTag rekey * Run tagsIncluded useTag rekey
* // no sessions * // no sessions
* 1 no no no * 1 no no no
* 2 no no no * 2 no no no
* // session * // session
* 3 yes (2) no no * 3 yes (2) no no
* 4 no yes no * 4 no yes no
* 5 yes (2) yes no * 5 yes (2) yes no
* 6 no yes no * 6 no yes no
* 7 no yes no * 7 no yes no
* // rekeying * // rekeying
* 8 yes (2) no no * 8 yes (2) no no
* 9 no yes no * 9 no yes no
* 10 yes (2) yes yes * 10 yes (2) yes yes
* 11 no yes no * 11 no yes no
* 12 no yes no * 12 no yes no
* // long session * // long session
* 13-1000 20 tags every 10 messages, rekey every 50 * 13-1000 20 tags every 10 messages, rekey every 50
*/ */
public class SessionEncryptionTest { 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 {
//test.testNoSessions(); //test.testNoSessions();
//test.testSessions(); //test.testSessions();
//test.testRekeying(); //test.testRekeying();
test.testLongSession(); test.testLongSession();
} catch (Throwable t) { } catch (Throwable t) {
_log.error("Error running tests", t); _log.error("Error running tests", t);
} }
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
} }
/** /**
* Run tagsIncluded useTag rekey * Run tagsIncluded useTag rekey
* 1 no no no * 1 no no no
* 2 no no no * 2 no no no
*/ */
public void testNoSessions() throws Exception { public void testNoSessions() throws Exception {
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
_log.error("FAILED: No sessions msg 2"); _log.error("FAILED: No sessions msg 2");
} }
/** /**
* Run tagsIncluded useTag rekey * Run tagsIncluded useTag rekey
* 1 yes (2) no no * 1 yes (2) no no
* 2 no yes no * 2 no yes no
* 3 yes (2) yes no * 3 yes (2) yes no
* 4 no yes no * 4 no yes no
* 5 no yes no * 5 no yes no
*/ */
public void testSessions() throws Exception { public void testSessions() throws Exception {
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);
SessionTag tag3 = new SessionTag(true); SessionTag tag3 = new SessionTag(true);
SessionTag tag4 = new SessionTag(true); SessionTag tag4 = new SessionTag(true);
HashSet firstTags = new HashSet(); HashSet firstTags = new HashSet();
firstTags.add(tag1); firstTags.add(tag1);
firstTags.add(tag2); firstTags.add(tag2);
HashSet secondTags = new HashSet(); HashSet secondTags = new HashSet();
secondTags.add(tag3); secondTags.add(tag3);
secondTags.add(tag4); secondTags.add(tag4);
byte[] msg1 = "msg 1".getBytes(); byte[] msg1 = "msg 1".getBytes();
byte[] msg2 = "msg 2".getBytes(); byte[] msg2 = "msg 2".getBytes();
byte[] msg3 = "msg 3".getBytes(); byte[] msg3 = "msg 3".getBytes();
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 {
_log.error("FAILED: Sessions msg 1"); _log.error("FAILED: Sessions msg 1");
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 {
_log.error("FAILED: Sessions msg 2"); _log.error("FAILED: Sessions msg 2");
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");
return; return;
} }
if (curKey == null) { if (curKey == null) {
_log.error("Not able to consume next KEY for message 3"); _log.error("Not able to consume next KEY for message 3");
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 {
_log.error("FAILED: Sessions msg 3"); _log.error("FAILED: Sessions msg 3");
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");
return; return;
} }
if (curKey == null) { if (curKey == null) {
_log.error("Not able to consume next KEY for message 4"); _log.error("Not able to consume next KEY for message 4");
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 {
_log.error("FAILED: Sessions msg 4"); _log.error("FAILED: Sessions msg 4");
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");
return; return;
} }
if (curKey == null) { if (curKey == null) {
_log.error("Not able to consume next KEY for message 5"); _log.error("Not able to consume next KEY for message 5");
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 {
_log.error("FAILED: Sessions msg 5"); _log.error("FAILED: Sessions msg 5");
return; return;
} }
} }
/** /**
* Run tagsIncluded useTag rekey * Run tagsIncluded useTag rekey
* 1 yes (2) no no * 1 yes (2) no no
* 2 no yes no * 2 no yes no
* 3 yes (2) yes yes * 3 yes (2) yes yes
* 4 no yes no * 4 no yes no
* 5 no yes no * 5 no yes no
*/ */
public void testRekeying() throws Exception { public void testRekeying() throws Exception {
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);
SessionTag tag2 = new SessionTag(true); SessionTag tag2 = new SessionTag(true);
SessionTag tag3 = new SessionTag(true); SessionTag tag3 = new SessionTag(true);
SessionTag tag4 = new SessionTag(true); SessionTag tag4 = new SessionTag(true);
HashSet firstTags = new HashSet(); HashSet firstTags = new HashSet();
firstTags.add(tag1); firstTags.add(tag1);
firstTags.add(tag2); firstTags.add(tag2);
HashSet secondTags = new HashSet(); HashSet secondTags = new HashSet();
secondTags.add(tag3); secondTags.add(tag3);
secondTags.add(tag4); secondTags.add(tag4);
byte[] msg1 = "msg 1".getBytes(); byte[] msg1 = "msg 1".getBytes();
byte[] msg2 = "msg 2".getBytes(); byte[] msg2 = "msg 2".getBytes();
byte[] msg3 = "msg 3".getBytes(); byte[] msg3 = "msg 3".getBytes();
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 {
_log.error("FAILED: Sessions msg 1"); _log.error("FAILED: Sessions msg 1");
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 {
_log.error("FAILED: Sessions msg 2"); _log.error("FAILED: Sessions msg 2");
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");
return; return;
} }
if (curKey == null) { if (curKey == null) {
_log.error("Not able to consume next KEY for message 3"); _log.error("Not able to consume next KEY for message 3");
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 {
_log.error("FAILED: Sessions msg 3"); _log.error("FAILED: Sessions msg 3");
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");
return; return;
} }
if (curKey == null) { if (curKey == null) {
_log.error("Not able to consume next KEY for message 4"); _log.error("Not able to consume next KEY for message 4");
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 {
_log.error("FAILED: Sessions msg 4"); _log.error("FAILED: Sessions msg 4");
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");
return; return;
} }
if (curKey == null) { if (curKey == null) {
_log.error("Not able to consume next KEY for message 5"); _log.error("Not able to consume next KEY for message 5");
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 {
_log.error("FAILED: Sessions msg 5"); _log.error("FAILED: Sessions msg 5");
return; return;
} }
} }
/** /**
* 20 tags every 10 messages, rekey every 50 * 20 tags every 10 messages, rekey every 50
*/ */
public void testLongSession() throws Exception { public void testLongSession() throws Exception {
int num = 1000; int num = 1000;
long start = Clock.getInstance().now(); long start = Clock.getInstance().now();
testLongSession(num); testLongSession(num);
long end = Clock.getInstance().now(); long end = Clock.getInstance().now();
long time = end - start; long time = end - start;
float msEach = (float)num / time; float msEach = (float)num / time;
_log.error("Test long session duration: " + num + " messages in " + time + "ms (or " + msEach + "ms each)"); _log.error("Test long session duration: " + num + " messages in " + time + "ms (or " + msEach + "ms each)");
} }
public void testLongSession(int numMsgs) throws Exception { public void testLongSession(int numMsgs) throws Exception {
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");
} else { } else {
_log.info("Tags already available: " + availTags + " curTag: " + curTag); _log.info("Tags already available: " + availTags + " curTag: " + curTag);
} }
if (i % 50 == 0) if (i % 50 == 0)
nextKey = KeyGenerator.getInstance().generateSessionKey(); nextKey = KeyGenerator.getInstance().generateSessionKey();
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 {
_log.error("FAILED: Long session msg " + i); _log.error("FAILED: Long session msg " + i);
return; return;
} }
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);
} }
} }
} }
} }
private Set generateNewTags(int numTags) { private Set generateNewTags(int numTags) {
Set tags = new HashSet(numTags); Set tags = new HashSet(numTags);
for (int i = 0; i < numTags; i++) for (int i = 0; i < numTags; i++)
tags.add(new SessionTag(true)); tags.add(new SessionTag(true));
return tags; return 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

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -15,6 +15,7 @@ import java.io.InputStream;
import net.i2p.data.DataFormatException; import net.i2p.data.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,8 +27,9 @@ 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) {
_data = null; super(context);
_data = null;
} }
public byte[] getData() { return _data; } public byte[] getData() { return _data; }
@ -36,23 +38,23 @@ public class DataMessage extends I2NPMessageImpl {
public int getSize() { return _data.length; } public int getSize() { return _data.length; }
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 size = (int)DataHelper.readLong(in, 4); int size = (int)DataHelper.readLong(in, 4);
_data = new byte[size]; _data = new byte[size];
int read = read(in, _data); int read = read(in, _data);
if (read != size) if (read != size)
throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")"); throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")");
} 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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream((_data != null ? _data.length + 4 : 4)); ByteArrayOutputStream os = new ByteArrayOutputStream((_data != null ? _data.length + 4 : 4));
try { try {
DataHelper.writeLong(os, 4, (_data != null ? _data.length : 0)); DataHelper.writeLong(os, 4, (_data != null ? _data.length : 0));
os.write(_data); os.write(_data);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -62,7 +64,7 @@ public class DataMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getData()); return DataHelper.hashCode(getData());
} }
public boolean equals(Object object) { public boolean equals(Object object) {
@ -74,7 +76,7 @@ public class DataMessage extends I2NPMessageImpl {
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[DataMessage: "); buf.append("[DataMessage: ");
buf.append("\n\tData: ").append(DataHelper.toString(getData(), 64)); buf.append("\n\tData: ").append(DataHelper.toString(getData(), 64));

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

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -21,6 +21,7 @@ import net.i2p.data.Hash;
import net.i2p.data.RouterInfo; import net.i2p.data.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,10 +37,11 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
private TunnelId _replyTunnel; private TunnelId _replyTunnel;
private Set _dontIncludePeers; private Set _dontIncludePeers;
public DatabaseLookupMessage() { public DatabaseLookupMessage(I2PAppContext context) {
setSearchKey(null); super(context);
setFrom(null); setSearchKey(null);
setDontIncludePeers(null); setFrom(null);
setDontIncludePeers(null);
} }
/** /**
@ -68,63 +70,63 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
* @return Set of Hash objects, each of which is the H(routerIdentity) to skip * @return Set of Hash objects, each of which is the H(routerIdentity) to skip
*/ */
public Set getDontIncludePeers() { return _dontIncludePeers; } public Set getDontIncludePeers() { return _dontIncludePeers; }
public void setDontIncludePeers(Set peers) { public void setDontIncludePeers(Set peers) {
if (peers != null) if (peers != null)
_dontIncludePeers = new HashSet(peers); _dontIncludePeers = new HashSet(peers);
else else
_dontIncludePeers = null; _dontIncludePeers = null;
} }
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 {
_key = new Hash(); _key = new Hash();
_key.readBytes(in); _key.readBytes(in);
_from = new RouterInfo(); _from = new RouterInfo();
_from.readBytes(in); _from.readBytes(in);
boolean tunnelSpecified = DataHelper.readBoolean(in).booleanValue(); boolean tunnelSpecified = DataHelper.readBoolean(in).booleanValue();
if (tunnelSpecified) { if (tunnelSpecified) {
_replyTunnel = new TunnelId(); _replyTunnel = new TunnelId();
_replyTunnel.readBytes(in); _replyTunnel.readBytes(in);
} }
int numPeers = (int)DataHelper.readLong(in, 2); int numPeers = (int)DataHelper.readLong(in, 2);
if ( (numPeers < 0) || (numPeers >= (1<<16) ) ) if ( (numPeers < 0) || (numPeers >= (1<<16) ) )
throw new DataFormatException("Invalid number of peers - " + numPeers); throw new DataFormatException("Invalid number of peers - " + numPeers);
Set peers = new HashSet(numPeers); Set peers = new HashSet(numPeers);
for (int i = 0; i < numPeers; i++) { for (int i = 0; i < numPeers; i++) {
Hash peer = new Hash(); Hash peer = new Hash();
peer.readBytes(in); peer.readBytes(in);
peers.add(peer); peers.add(peer);
} }
_dontIncludePeers = peers; _dontIncludePeers = peers;
} 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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if (_key == null) throw new I2NPMessageException("Key being searched for not specified"); if (_key == null) throw new I2NPMessageException("Key being searched for not specified");
if (_from == null) throw new I2NPMessageException("From address not specified"); if (_from == null) throw new I2NPMessageException("From address not specified");
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
_key.writeBytes(os); _key.writeBytes(os);
_from.writeBytes(os); _from.writeBytes(os);
if (_replyTunnel != null) { if (_replyTunnel != null) {
DataHelper.writeBoolean(os, Boolean.TRUE); DataHelper.writeBoolean(os, Boolean.TRUE);
_replyTunnel.writeBytes(os); _replyTunnel.writeBytes(os);
} else { } else {
DataHelper.writeBoolean(os, Boolean.FALSE); DataHelper.writeBoolean(os, Boolean.FALSE);
} }
if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) { if ( (_dontIncludePeers == null) || (_dontIncludePeers.size() <= 0) ) {
DataHelper.writeLong(os, 2, 0); DataHelper.writeLong(os, 2, 0);
} else { } else {
DataHelper.writeLong(os, 2, _dontIncludePeers.size()); DataHelper.writeLong(os, 2, _dontIncludePeers.size());
for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) { for (Iterator iter = _dontIncludePeers.iterator(); iter.hasNext(); ) {
Hash peer = (Hash)iter.next(); Hash peer = (Hash)iter.next();
peer.writeBytes(os); peer.writeBytes(os);
} }
} }
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -134,25 +136,25 @@ public class DatabaseLookupMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getSearchKey()) + return DataHelper.hashCode(getSearchKey()) +
DataHelper.hashCode(getFrom()) + DataHelper.hashCode(getFrom()) +
DataHelper.hashCode(getReplyTunnel()) + DataHelper.hashCode(getReplyTunnel()) +
DataHelper.hashCode(_dontIncludePeers); DataHelper.hashCode(_dontIncludePeers);
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof DatabaseLookupMessage) ) { if ( (object != null) && (object instanceof DatabaseLookupMessage) ) {
DatabaseLookupMessage msg = (DatabaseLookupMessage)object; DatabaseLookupMessage msg = (DatabaseLookupMessage)object;
return DataHelper.eq(getSearchKey(),msg.getSearchKey()) && return DataHelper.eq(getSearchKey(),msg.getSearchKey()) &&
DataHelper.eq(getFrom(),msg.getFrom()) && DataHelper.eq(getFrom(),msg.getFrom()) &&
DataHelper.eq(getReplyTunnel(),msg.getReplyTunnel()) && DataHelper.eq(getReplyTunnel(),msg.getReplyTunnel()) &&
DataHelper.eq(_dontIncludePeers,msg.getDontIncludePeers()); DataHelper.eq(_dontIncludePeers,msg.getDontIncludePeers());
} else { } else {
return false; return false;
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[DatabaseLookupMessage: "); buf.append("[DatabaseLookupMessage: ");
buf.append("\n\tSearch Key: ").append(getSearchKey()); buf.append("\n\tSearch Key: ").append(getSearchKey());

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -21,10 +21,11 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.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
* search (DatabaseFindNearest or DatabaseLookup) when it doesn't have the value, * search (DatabaseFindNearest or DatabaseLookup) when it doesn't have the value,
* specifying what routers it would search. * specifying what routers it would search.
* *
* @author jrandom * @author jrandom
@ -36,10 +37,11 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
private List _routerInfoStructures; private List _routerInfoStructures;
private Hash _from; private Hash _from;
public DatabaseSearchReplyMessage() { public DatabaseSearchReplyMessage(I2PAppContext context) {
setSearchKey(null); super(context);
_routerInfoStructures = new ArrayList(); setSearchKey(null);
setFromHash(null); _routerInfoStructures = new ArrayList();
setFromHash(null);
} }
/** /**
@ -57,58 +59,58 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
public void setFromHash(Hash from) { _from = from; } public void setFromHash(Hash from) { _from = from; }
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 {
_key = new Hash(); _key = new Hash();
_key.readBytes(in); _key.readBytes(in);
int compressedLength = (int)DataHelper.readLong(in, 2); int compressedLength = (int)DataHelper.readLong(in, 2);
byte compressedData[] = new byte[compressedLength]; byte compressedData[] = new byte[compressedLength];
int read = DataHelper.read(in, compressedData); int read = DataHelper.read(in, compressedData);
if (read != compressedLength) if (read != compressedLength)
throw new IOException("Not enough data to decompress"); throw new IOException("Not enough data to decompress");
byte decompressedData[] = DataHelper.decompress(compressedData); byte decompressedData[] = DataHelper.decompress(compressedData);
ByteArrayInputStream bais = new ByteArrayInputStream(decompressedData); ByteArrayInputStream bais = new ByteArrayInputStream(decompressedData);
int num = (int)DataHelper.readLong(bais, 1); int num = (int)DataHelper.readLong(bais, 1);
_routerInfoStructures.clear(); _routerInfoStructures.clear();
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
RouterInfo info = new RouterInfo(); RouterInfo info = new RouterInfo();
info.readBytes(bais); info.readBytes(bais);
addReply(info); addReply(info);
} }
_from = new Hash(); _from = new Hash();
_from.readBytes(in); _from.readBytes(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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if (_key == null) if (_key == null)
throw new I2NPMessageException("Key in reply to not specified"); throw new I2NPMessageException("Key in reply to not specified");
if (_routerInfoStructures == null) if (_routerInfoStructures == null)
throw new I2NPMessageException("RouterInfo replies are null"); throw new I2NPMessageException("RouterInfo replies are null");
if (_routerInfoStructures.size() <= 0) if (_routerInfoStructures.size() <= 0)
throw new I2NPMessageException("No replies specified in SearchReply! Always include oneself!"); throw new I2NPMessageException("No replies specified in SearchReply! Always include oneself!");
if (_from == null) if (_from == null)
throw new I2NPMessageException("No 'from' address specified!"); throw new I2NPMessageException("No 'from' address specified!");
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
_key.writeBytes(os); _key.writeBytes(os);
ByteArrayOutputStream baos = new ByteArrayOutputStream(512); ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
DataHelper.writeLong(baos, 1, _routerInfoStructures.size()); DataHelper.writeLong(baos, 1, _routerInfoStructures.size());
for (int i = 0; i < getNumReplies(); i++) { for (int i = 0; i < getNumReplies(); i++) {
RouterInfo info = getReply(i); RouterInfo info = getReply(i);
info.writeBytes(baos); info.writeBytes(baos);
} }
byte compressed[] = DataHelper.compress(baos.toByteArray()); byte compressed[] = DataHelper.compress(baos.toByteArray());
DataHelper.writeLong(os, 2, compressed.length); DataHelper.writeLong(os, 2, compressed.length);
os.write(compressed); os.write(compressed);
_from.writeBytes(os); _from.writeBytes(os);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -121,27 +123,27 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl {
if ( (object != null) && (object instanceof DatabaseSearchReplyMessage) ) { if ( (object != null) && (object instanceof DatabaseSearchReplyMessage) ) {
DatabaseSearchReplyMessage msg = (DatabaseSearchReplyMessage)object; DatabaseSearchReplyMessage msg = (DatabaseSearchReplyMessage)object;
return DataHelper.eq(getSearchKey(),msg.getSearchKey()) && return DataHelper.eq(getSearchKey(),msg.getSearchKey()) &&
DataHelper.eq(getFromHash(),msg.getFromHash()) && DataHelper.eq(getFromHash(),msg.getFromHash()) &&
DataHelper.eq(_routerInfoStructures,msg._routerInfoStructures); DataHelper.eq(_routerInfoStructures,msg._routerInfoStructures);
} else { } else {
return false; return false;
} }
} }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getSearchKey()) + return DataHelper.hashCode(getSearchKey()) +
DataHelper.hashCode(getFromHash()) + DataHelper.hashCode(getFromHash()) +
DataHelper.hashCode(_routerInfoStructures); DataHelper.hashCode(_routerInfoStructures);
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[DatabaseSearchReplyMessage: "); buf.append("[DatabaseSearchReplyMessage: ");
buf.append("\n\tSearch Key: ").append(getSearchKey()); buf.append("\n\tSearch Key: ").append(getSearchKey());
buf.append("\n\tReplies: # = ").append(getNumReplies()); buf.append("\n\tReplies: # = ").append(getNumReplies());
for (int i = 0; i < getNumReplies(); i++) { for (int i = 0; i < getNumReplies(); i++) {
buf.append("\n\t\tReply [").append(i).append("]: ").append(getReply(i)); buf.append("\n\t\tReply [").append(i).append("]: ").append(getReply(i));
} }
buf.append("\n\tFrom: ").append(getFromHash()); buf.append("\n\tFrom: ").append(getFromHash());
buf.append("]"); buf.append("]");
return buf.toString(); return buf.toString();

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -19,9 +19,10 @@ import net.i2p.data.Hash;
import net.i2p.data.LeaseSet; import net.i2p.data.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
* database reachability, as well as the reply message sent back. * database reachability, as well as the reply message sent back.
* *
* @author jrandom * @author jrandom
@ -37,11 +38,12 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
public final static int KEY_TYPE_ROUTERINFO = 0; public final static int KEY_TYPE_ROUTERINFO = 0;
public final static int KEY_TYPE_LEASESET = 1; public final static int KEY_TYPE_LEASESET = 1;
public DatabaseStoreMessage() { public DatabaseStoreMessage(I2PAppContext context) {
setValueType(-1); super(context);
setKey(null); setValueType(-1);
setLeaseSet(null); setKey(null);
setRouterInfo(null); setLeaseSet(null);
setRouterInfo(null);
} }
/** /**
@ -56,10 +58,10 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
* *
*/ */
public RouterInfo getRouterInfo() { return _info; } public RouterInfo getRouterInfo() { return _info; }
public void setRouterInfo(RouterInfo routerInfo) { public void setRouterInfo(RouterInfo routerInfo) {
_info = routerInfo; _info = routerInfo;
if (_info != null) if (_info != null)
setValueType(KEY_TYPE_ROUTERINFO); setValueType(KEY_TYPE_ROUTERINFO);
} }
/** /**
@ -67,14 +69,14 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
* *
*/ */
public LeaseSet getLeaseSet() { return _leaseSet; } public LeaseSet getLeaseSet() { return _leaseSet; }
public void setLeaseSet(LeaseSet leaseSet) { public void setLeaseSet(LeaseSet leaseSet) {
_leaseSet = leaseSet; _leaseSet = leaseSet;
if (_leaseSet != null) if (_leaseSet != null)
setValueType(KEY_TYPE_LEASESET); setValueType(KEY_TYPE_LEASESET);
} }
/** /**
* Defines type of key being stored in the network database - * Defines type of key being stored in the network database -
* either KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET * either KEY_TYPE_ROUTERINFO or KEY_TYPE_LEASESET
* *
*/ */
@ -82,52 +84,52 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
public void setValueType(int type) { _type = type; } public void setValueType(int type) { _type = type; }
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 {
_key = new Hash(); _key = new Hash();
_key.readBytes(in); _key.readBytes(in);
_log.debug("Hash read: " + _key.toBase64()); _log.debug("Hash read: " + _key.toBase64());
_type = (int)DataHelper.readLong(in, 1); _type = (int)DataHelper.readLong(in, 1);
if (_type == KEY_TYPE_LEASESET) { if (_type == KEY_TYPE_LEASESET) {
_leaseSet = new LeaseSet(); _leaseSet = new LeaseSet();
_leaseSet.readBytes(in); _leaseSet.readBytes(in);
} else if (_type == KEY_TYPE_ROUTERINFO) { } else if (_type == KEY_TYPE_ROUTERINFO) {
_info = new RouterInfo(); _info = new RouterInfo();
int compressedSize = (int)DataHelper.readLong(in, 2); int compressedSize = (int)DataHelper.readLong(in, 2);
byte compressed[] = new byte[compressedSize]; byte compressed[] = new byte[compressedSize];
int read = DataHelper.read(in, compressed); int read = DataHelper.read(in, compressed);
if (read != compressedSize) if (read != compressedSize)
throw new I2NPMessageException("Invalid compressed data size"); throw new I2NPMessageException("Invalid compressed data size");
ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed)); ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed));
_info.readBytes(bais); _info.readBytes(bais);
} else { } else {
throw new I2NPMessageException("Invalid type of key read from the structure - " + _type); throw new I2NPMessageException("Invalid type of key read from the structure - " + _type);
} }
} 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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if (_key == null) throw new I2NPMessageException("Invalid key"); if (_key == null) throw new I2NPMessageException("Invalid key");
if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type"); if ( (_type != KEY_TYPE_LEASESET) && (_type != KEY_TYPE_ROUTERINFO) ) throw new I2NPMessageException("Invalid key type");
if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set"); if ( (_type == KEY_TYPE_LEASESET) && (_leaseSet == null) ) throw new I2NPMessageException("Missing lease set");
if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info"); if ( (_type == KEY_TYPE_ROUTERINFO) && (_info == null) ) throw new I2NPMessageException("Missing router info");
ByteArrayOutputStream os = new ByteArrayOutputStream(256); ByteArrayOutputStream os = new ByteArrayOutputStream(256);
try { try {
_key.writeBytes(os); _key.writeBytes(os);
DataHelper.writeLong(os, 1, _type); DataHelper.writeLong(os, 1, _type);
if (_type == KEY_TYPE_LEASESET) { if (_type == KEY_TYPE_LEASESET) {
_leaseSet.writeBytes(os); _leaseSet.writeBytes(os);
} else if (_type == KEY_TYPE_ROUTERINFO) { } else if (_type == KEY_TYPE_ROUTERINFO) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024); ByteArrayOutputStream baos = new ByteArrayOutputStream(4*1024);
_info.writeBytes(baos); _info.writeBytes(baos);
byte uncompressed[] = baos.toByteArray(); byte uncompressed[] = baos.toByteArray();
byte compressed[] = DataHelper.compress(uncompressed); byte compressed[] = DataHelper.compress(uncompressed);
DataHelper.writeLong(os, 2, compressed.length); DataHelper.writeLong(os, 2, compressed.length);
os.write(compressed); os.write(compressed);
} }
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -137,29 +139,29 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getKey()) + return DataHelper.hashCode(getKey()) +
DataHelper.hashCode(getLeaseSet()) + DataHelper.hashCode(getLeaseSet()) +
DataHelper.hashCode(getRouterInfo()) + DataHelper.hashCode(getRouterInfo()) +
getValueType(); getValueType();
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof DatabaseStoreMessage) ) { if ( (object != null) && (object instanceof DatabaseStoreMessage) ) {
DatabaseStoreMessage msg = (DatabaseStoreMessage)object; DatabaseStoreMessage msg = (DatabaseStoreMessage)object;
return DataHelper.eq(getKey(),msg.getKey()) && return DataHelper.eq(getKey(),msg.getKey()) &&
DataHelper.eq(getLeaseSet(),msg.getLeaseSet()) && DataHelper.eq(getLeaseSet(),msg.getLeaseSet()) &&
DataHelper.eq(getRouterInfo(),msg.getRouterInfo()) && DataHelper.eq(getRouterInfo(),msg.getRouterInfo()) &&
DataHelper.eq(getValueType(),msg.getValueType()); DataHelper.eq(getValueType(),msg.getValueType());
} else { } else {
return false; return false;
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[DatabaseStoreMessage: "); buf.append("[DatabaseStoreMessage: ");
buf.append("\n\tExpiration: ").append(getMessageExpiration()); buf.append("\n\tExpiration: ").append(getMessageExpiration());
buf.append("\n\tUnique ID: ").append(getUniqueId()); buf.append("\n\tUnique ID: ").append(getUniqueId());
buf.append("\n\tKey: ").append(getKey()); buf.append("\n\tKey: ").append(getKey());
buf.append("\n\tValue Type: ").append(getValueType()); buf.append("\n\tValue Type: ").append(getValueType());
buf.append("\n\tRouter Info: ").append(getRouterInfo()); buf.append("\n\tRouter Info: ").append(getRouterInfo());

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -16,6 +16,7 @@ import java.util.Date;
import net.i2p.data.DataFormatException; import net.i2p.data.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,9 +30,10 @@ public class DeliveryStatusMessage extends I2NPMessageImpl {
private long _id; private long _id;
private Date _arrival; private Date _arrival;
public DeliveryStatusMessage() { public DeliveryStatusMessage(I2PAppContext context) {
setMessageId(-1); super(context);
setArrival(null); setMessageId(-1);
setArrival(null);
} }
public long getMessageId() { return _id; } public long getMessageId() { return _id; }
@ -41,22 +43,22 @@ public class DeliveryStatusMessage extends I2NPMessageImpl {
public void setArrival(Date arrival) { _arrival = arrival; } public void setArrival(Date arrival) { _arrival = arrival; }
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 {
_id = DataHelper.readLong(in, 4); _id = DataHelper.readLong(in, 4);
_arrival = DataHelper.readDate(in); _arrival = DataHelper.readDate(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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_id < 0) || (_arrival == null) ) throw new I2NPMessageException("Not enough data to write out"); if ( (_id < 0) || (_arrival == null) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
DataHelper.writeLong(os, 4, _id); DataHelper.writeLong(os, 4, _id);
DataHelper.writeDate(os, _arrival); DataHelper.writeDate(os, _arrival);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -66,21 +68,21 @@ public class DeliveryStatusMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return (int)getMessageId() + return (int)getMessageId() +
DataHelper.hashCode(getArrival()); DataHelper.hashCode(getArrival());
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof DeliveryStatusMessage) ) { if ( (object != null) && (object instanceof DeliveryStatusMessage) ) {
DeliveryStatusMessage msg = (DeliveryStatusMessage)object; DeliveryStatusMessage msg = (DeliveryStatusMessage)object;
return DataHelper.eq(getMessageId(),msg.getMessageId()) && return DataHelper.eq(getMessageId(),msg.getMessageId()) &&
DataHelper.eq(getArrival(),msg.getArrival()); DataHelper.eq(getArrival(),msg.getArrival());
} else { } else {
return false; return false;
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[DeliveryStatusMessage: "); buf.append("[DeliveryStatusMessage: ");
buf.append("\n\tMessage ID: ").append(getMessageId()); buf.append("\n\tMessage ID: ").append(getMessageId());

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -18,6 +18,7 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.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,30 +36,34 @@ 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;
/** /**
* A DeliveryStatusMessage is requested with the source route block using * A DeliveryStatusMessage is requested with the source route block using
* the cloveId as the id received * the cloveId as the id received
* *
*/ */
public final static int ACTION_STATUS = 1; public final static int ACTION_STATUS = 1;
/** /**
* No DeliveryStatusMessage is requested, but the source route block is * No DeliveryStatusMessage is requested, but the source route block is
* included for message specific replies * included for message specific replies
* *
*/ */
public final static int ACTION_MESSAGE_SPECIFIC = 2; public final static int ACTION_MESSAGE_SPECIFIC = 2;
public GarlicClove() { public GarlicClove(RouterContext context) {
setInstructions(null); _context = context;
setData(null); _log = context.logManager().getLog(GarlicClove.class);
setCloveId(-1); _handler = new I2NPMessageHandler(context);
setExpiration(null); setInstructions(null);
setCertificate(null); setData(null);
setSourceRouteBlockAction(ACTION_NONE); setCloveId(-1);
setSourceRouteBlock(null); setExpiration(null);
setCertificate(null);
setSourceRouteBlockAction(ACTION_NONE);
setSourceRouteBlock(null);
} }
public DeliveryInstructions getInstructions() { return _instructions; } public DeliveryInstructions getInstructions() { return _instructions; }
@ -76,94 +82,94 @@ public class GarlicClove extends DataStructureImpl {
public void setSourceRouteBlock(SourceRouteBlock block) { _sourceRouteBlock = block; } public void setSourceRouteBlock(SourceRouteBlock block) { _sourceRouteBlock = block; }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
_instructions = new DeliveryInstructions(); _instructions = new DeliveryInstructions();
_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);
} }
_cloveId = DataHelper.readLong(in, 4); _cloveId = DataHelper.readLong(in, 4);
_expiration = DataHelper.readDate(in); _expiration = DataHelper.readDate(in);
_log.debug("CloveID read: " + _cloveId + " expiration read: " + _expiration); _log.debug("CloveID read: " + _cloveId + " expiration read: " + _expiration);
_certificate = new Certificate(); _certificate = new Certificate();
_certificate.readBytes(in); _certificate.readBytes(in);
_log.debug("Read cert: " + _certificate); _log.debug("Read cert: " + _certificate);
int replyStyle = (int)DataHelper.readLong(in, 1); int replyStyle = (int)DataHelper.readLong(in, 1);
setSourceRouteBlockAction(replyStyle); setSourceRouteBlockAction(replyStyle);
if (replyStyle != ACTION_NONE) { if (replyStyle != ACTION_NONE) {
_sourceRouteBlock = new SourceRouteBlock(); _sourceRouteBlock = new SourceRouteBlock();
_sourceRouteBlock.readBytes(in); _sourceRouteBlock.readBytes(in);
} }
} }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { public void writeBytes(OutputStream out) throws DataFormatException, IOException {
StringBuffer error = new StringBuffer(); StringBuffer error = new StringBuffer();
if (_instructions == null) if (_instructions == null)
error.append("No instructions "); error.append("No instructions ");
if (_msg == null) if (_msg == null)
error.append("No message "); error.append("No message ");
if (_cloveId < 0) if (_cloveId < 0)
error.append("CloveID < 0 [").append(_cloveId).append("] "); error.append("CloveID < 0 [").append(_cloveId).append("] ");
if (_expiration == null) if (_expiration == null)
error.append("Expiration is null "); error.append("Expiration is null ");
if (_certificate == null) if (_certificate == null)
error.append("Certificate is null "); error.append("Certificate is null ");
if (_replyAction < 0) if (_replyAction < 0)
error.append("Reply action is < 0 [").append(_replyAction).append("] ");; error.append("Reply action is < 0 [").append(_replyAction).append("] ");;
if (error.length() > 0) if (error.length() > 0)
throw new DataFormatException(error.toString()); throw new DataFormatException(error.toString());
if ( (_replyAction != 0) && (_sourceRouteBlock == null) ) if ( (_replyAction != 0) && (_sourceRouteBlock == null) )
throw new DataFormatException("Source route block must be specified for non-null action"); throw new DataFormatException("Source route block must be specified for non-null action");
_instructions.writeBytes(out); _instructions.writeBytes(out);
_log.debug("Wrote instructions: " + _instructions); _log.debug("Wrote instructions: " + _instructions);
_msg.writeBytes(out); _msg.writeBytes(out);
DataHelper.writeLong(out, 4, _cloveId); DataHelper.writeLong(out, 4, _cloveId);
DataHelper.writeDate(out, _expiration); DataHelper.writeDate(out, _expiration);
_log.debug("CloveID written: " + _cloveId + " expiration written: " + _expiration); _log.debug("CloveID written: " + _cloveId + " expiration written: " + _expiration);
_certificate.writeBytes(out); _certificate.writeBytes(out);
_log.debug("Written cert: " + _certificate); _log.debug("Written cert: " + _certificate);
DataHelper.writeLong(out, 1, _replyAction); DataHelper.writeLong(out, 1, _replyAction);
if ( (_replyAction != 0) && (_sourceRouteBlock != null) ) if ( (_replyAction != 0) && (_sourceRouteBlock != null) )
_sourceRouteBlock.writeBytes(out); _sourceRouteBlock.writeBytes(out);
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof GarlicClove)) if ( (obj == null) || !(obj instanceof GarlicClove))
return false; return false;
GarlicClove clove = (GarlicClove)obj; GarlicClove clove = (GarlicClove)obj;
return DataHelper.eq(getCertificate(), clove.getCertificate()) && return DataHelper.eq(getCertificate(), clove.getCertificate()) &&
DataHelper.eq(getCloveId(), clove.getCloveId()) && DataHelper.eq(getCloveId(), clove.getCloveId()) &&
DataHelper.eq(getData(), clove.getData()) && DataHelper.eq(getData(), clove.getData()) &&
DataHelper.eq(getExpiration(), clove.getExpiration()) && DataHelper.eq(getExpiration(), clove.getExpiration()) &&
DataHelper.eq(getInstructions(), clove.getInstructions()) && DataHelper.eq(getInstructions(), clove.getInstructions()) &&
DataHelper.eq(getSourceRouteBlock(), clove.getSourceRouteBlock()) && DataHelper.eq(getSourceRouteBlock(), clove.getSourceRouteBlock()) &&
(getSourceRouteBlockAction() == clove.getSourceRouteBlockAction()); (getSourceRouteBlockAction() == clove.getSourceRouteBlockAction());
} }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getCertificate()) + return DataHelper.hashCode(getCertificate()) +
(int)getCloveId() + (int)getCloveId() +
DataHelper.hashCode(getData()) + DataHelper.hashCode(getData()) +
DataHelper.hashCode(getExpiration()) + DataHelper.hashCode(getExpiration()) +
DataHelper.hashCode(getInstructions()) + DataHelper.hashCode(getInstructions()) +
DataHelper.hashCode(getSourceRouteBlock()) + DataHelper.hashCode(getSourceRouteBlock()) +
getSourceRouteBlockAction(); getSourceRouteBlockAction();
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append("[GarlicClove: "); buf.append("[GarlicClove: ");
buf.append("\n\tInstructions: ").append(getInstructions()); buf.append("\n\tInstructions: ").append(getInstructions());
buf.append("\n\tCertificate: ").append(getCertificate()); buf.append("\n\tCertificate: ").append(getCertificate());
buf.append("\n\tClove ID: ").append(getCloveId()); buf.append("\n\tClove ID: ").append(getCloveId());
buf.append("\n\tExpiration: ").append(getExpiration()); buf.append("\n\tExpiration: ").append(getExpiration());
buf.append("\n\tSource route style: ").append(getSourceRouteBlockAction()); buf.append("\n\tSource route style: ").append(getSourceRouteBlockAction());
buf.append("\n\tSource route block: ").append(getSourceRouteBlock()); buf.append("\n\tSource route block: ").append(getSourceRouteBlock());
buf.append("\n\tData: ").append(getData()); buf.append("\n\tData: ").append(getData());
buf.append("]"); buf.append("]");
return buf.toString(); return buf.toString();
} }
} }

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -15,6 +15,7 @@ import java.io.InputStream;
import net.i2p.data.DataFormatException; import net.i2p.data.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,33 +27,34 @@ 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) {
setData(null); super(context);
setData(null);
} }
public byte[] getData() { return _data; } public byte[] getData() { return _data; }
public void setData(byte[] data) { _data = data; } public void setData(byte[] data) { _data = data; }
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 {
long len = DataHelper.readLong(in, 4); long len = DataHelper.readLong(in, 4);
_data = new byte[(int)len]; _data = new byte[(int)len];
int read = read(in, _data); int read = read(in, _data);
if (read != len) if (read != len)
throw new I2NPMessageException("Incorrect size read"); throw new I2NPMessageException("Incorrect size read");
} 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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out"); if ( (_data == null) || (_data.length <= 0) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
DataHelper.writeLong(os, 4, _data.length); DataHelper.writeLong(os, 4, _data.length);
os.write(_data); os.write(_data);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -62,7 +64,7 @@ public class GarlicMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getData()); return DataHelper.hashCode(getData());
} }
public boolean equals(Object object) { public boolean equals(Object object) {
@ -74,7 +76,7 @@ public class GarlicMessage extends I2NPMessageImpl {
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[GarlicMessage: "); buf.append("[GarlicMessage: ");
buf.append("\n\tData length: ").append(getData().length).append(" bytes"); buf.append("\n\tData length: ").append(getData().length).append(" bytes");

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -16,20 +16,25 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.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.
* *
* @throws IOException if there is an IO problem reading from the stream * @throws IOException if there is an IO problem reading from the stream
* @throws I2NPMessageException if there is a problem handling the particular * @throws I2NPMessageException if there is a problem handling the particular
* message - if it is an unknown type or has improper formatting, etc. * message - if it is an unknown type or has improper formatting, etc.
@ -37,10 +42,10 @@ public class I2NPMessageHandler {
public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException { 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);
@ -50,31 +55,31 @@ public class I2NPMessageHandler {
public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; } public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; }
/** /**
* Yes, this is fairly ugly, but its the only place it ever happens. * Yes, this is fairly ugly, but its the only place it ever happens.
* *
*/ */
private static I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException { private I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException {
switch (type) { 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

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -19,6 +19,7 @@ import net.i2p.data.DataStructureImpl;
import net.i2p.util.Clock; import net.i2p.util.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);
} }
/** /**
@ -45,8 +49,8 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
protected abstract byte[] writeMessage() throws I2NPMessageException, IOException; protected abstract byte[] writeMessage() throws I2NPMessageException, IOException;
/** /**
* Read the body into the data structures, after the initial type byte and * Read the body into the data structures, after the initial type byte and
* the uniqueId / expiration, using the current class's format as defined by * the uniqueId / expiration, using the current class's format as defined by
* the I2NP specification * the I2NP specification
* *
* @param in stream to read from * @param in stream to read from
@ -58,35 +62,35 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
protected abstract void readMessage(InputStream in, int type) throws I2NPMessageException, IOException; protected abstract void readMessage(InputStream in, int type) throws I2NPMessageException, IOException;
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
try { try {
readBytes(in, -1); readBytes(in, -1);
} catch (I2NPMessageException ime) { } catch (I2NPMessageException ime) {
throw new DataFormatException("Bad bytes", ime); throw new DataFormatException("Bad bytes", ime);
} }
} }
public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException { public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException {
try { try {
if (type < 0) if (type < 0)
type = (int)DataHelper.readLong(in, 1); type = (int)DataHelper.readLong(in, 1);
_uniqueId = DataHelper.readLong(in, 4); _uniqueId = DataHelper.readLong(in, 4);
_expiration = DataHelper.readDate(in); _expiration = DataHelper.readDate(in);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the message header", dfe); throw new I2NPMessageException("Error reading the message header", dfe);
} }
_log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); _log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
readMessage(in, type); readMessage(in, type);
} }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { public void writeBytes(OutputStream out) throws DataFormatException, IOException {
try { try {
DataHelper.writeLong(out, 1, getType()); DataHelper.writeLong(out, 1, getType());
DataHelper.writeLong(out, 4, _uniqueId); DataHelper.writeLong(out, 4, _uniqueId);
DataHelper.writeDate(out, _expiration); DataHelper.writeDate(out, _expiration);
_log.debug("Writing bytes: type = " + getType() + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); _log.debug("Writing bytes: type = " + getType() + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration);
byte[] data = writeMessage(); byte[] data = writeMessage();
out.write(data); out.write(data);
} catch (I2NPMessageException ime) { } catch (I2NPMessageException ime) {
throw new DataFormatException("Error writing out the I2NP message data", ime); throw new DataFormatException("Error writing out the I2NP message data", ime);
} }
} }
/** /**

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -13,9 +13,10 @@ import java.io.InputStream;
import net.i2p.util.I2PThread; import net.i2p.util.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
* {@link I2NPMessageHandler I2NPMessageHandler}) and passes out events to a registered * {@link I2NPMessageHandler I2NPMessageHandler}) and passes out events to a registered
* listener, where events are either messages being received, exceptions being * listener, where events are either messages being received, exceptions being
* thrown, or the connection being closed. Routers should use this rather * thrown, or the connection being closed. Routers should use this rather
@ -24,23 +25,26 @@ 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) {
_stream = stream; _context = context;
_log = context.logManager().getLog(I2NPMessageReader.class);
_stream = stream;
setListener(lsnr); setListener(lsnr);
_reader = new I2NPMessageReaderRunner(); _reader = new I2NPMessageReaderRunner();
_readerThread = new I2PThread(_reader); _readerThread = new I2PThread(_reader);
_readerThread.setName(name); _readerThread.setName(name);
_readerThread.setDaemon(true); _readerThread.setDaemon(true);
} }
public void setListener(I2NPMessageEventListener lsnr) { _listener = lsnr; } public void setListener(I2NPMessageEventListener lsnr) { _listener = lsnr; }
@ -50,7 +54,7 @@ public class I2NPMessageReader {
* Instruct the reader to begin reading messages off the stream * Instruct the reader to begin reading messages off the stream
* *
*/ */
public void startReading() { _readerThread.start(); } public void startReading() { _readerThread.start(); }
/** /**
* Have the already started reader pause its reading indefinitely * Have the already started reader pause its reading indefinitely
* *
@ -62,7 +66,7 @@ public class I2NPMessageReader {
*/ */
public void resumeReading() { _reader.resumeRunner(); } public void resumeReading() { _reader.resumeRunner(); }
/** /**
* Cancel reading. * Cancel reading.
* *
*/ */
public void stopReading() { _reader.cancelRunner(); } public void stopReading() { _reader.cancelRunner(); }
@ -90,22 +94,22 @@ public class I2NPMessageReader {
* *
*/ */
public void disconnected(I2NPMessageReader reader); public void disconnected(I2NPMessageReader reader);
} }
private class I2NPMessageReaderRunner implements Runnable { private class I2NPMessageReaderRunner implements Runnable {
private boolean _doRun; private boolean _doRun;
private boolean _stayAlive; private boolean _stayAlive;
private I2NPMessageHandler _handler; private I2NPMessageHandler _handler;
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; }
public void cancelRunner() { public void cancelRunner() {
_doRun = false; _doRun = false;
_stayAlive = false; _stayAlive = false;
} }
public void run() { public void run() {
while (_stayAlive) { while (_stayAlive) {
@ -114,16 +118,16 @@ public class I2NPMessageReader {
try { try {
I2NPMessage msg = _handler.readMessage(_stream); I2NPMessage msg = _handler.readMessage(_stream);
if (msg != null) { if (msg != null) {
long msToRead = _handler.getLastReadTime(); long msToRead = _handler.getLastReadTime();
_listener.messageReceived(I2NPMessageReader.this, msg, msToRead); _listener.messageReceived(I2NPMessageReader.this, msg, msToRead);
} }
} catch (I2NPMessageException ime) { } catch (I2NPMessageException ime) {
//_log.warn("Error handling message", ime); //_log.warn("Error handling message", ime);
_listener.readError(I2NPMessageReader.this, ime); _listener.readError(I2NPMessageReader.this, ime);
_listener.disconnected(I2NPMessageReader.this); _listener.disconnected(I2NPMessageReader.this);
cancelRunner(); cancelRunner();
} catch (IOException ioe) { } catch (IOException ioe) {
_log.warn("IO Error handling message", ioe); _log.warn("IO Error handling message", ioe);
_listener.disconnected(I2NPMessageReader.this); _listener.disconnected(I2NPMessageReader.this);
cancelRunner(); cancelRunner();
} }

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;
/** /**
@ -46,14 +47,14 @@ public class SourceRouteBlock extends DataStructureImpl {
private long _decryptedExpiration; private long _decryptedExpiration;
public SourceRouteBlock() { public SourceRouteBlock() {
setRouter(null); setRouter(null);
setData(null); setData(null);
setKey(null); setKey(null);
setTag((byte[])null); setTag((byte[])null);
_decryptedInstructions = null; _decryptedInstructions = null;
_decryptedMessageId = -1; _decryptedMessageId = -1;
_decryptedCertificate = null; _decryptedCertificate = null;
_decryptedExpiration = -1; _decryptedExpiration = -1;
} }
/** /**
@ -92,9 +93,9 @@ public class SourceRouteBlock extends DataStructureImpl {
public byte[] getTag() { return _tag; } public byte[] getTag() { return _tag; }
public void setTag(SessionTag tag) { setTag(tag.getData()); } public void setTag(SessionTag tag) { setTag(tag.getData()); }
public void setTag(byte tag[]) { public void setTag(byte tag[]) {
if ( (tag != null) && (tag.length != SessionTag.BYTE_LENGTH) ) if ( (tag != null) && (tag.length != SessionTag.BYTE_LENGTH) )
throw new IllegalArgumentException("Tag must be either null or 32 bytes"); throw new IllegalArgumentException("Tag must be either null or 32 bytes");
_tag = tag; _tag = tag;
} }
/** /**
@ -126,100 +127,105 @@ 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,
try { long messageId, Certificate cert, long expiration,
ByteArrayOutputStream baos = new ByteArrayOutputStream(64); PublicKey replyThrough) throws DataFormatException {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(64);
_decryptedInstructions = instructions; _decryptedInstructions = instructions;
_decryptedMessageId = messageId; _decryptedMessageId = messageId;
_decryptedCertificate = cert; _decryptedCertificate = cert;
_decryptedExpiration = expiration; _decryptedExpiration = expiration;
instructions.writeBytes(baos);
DataHelper.writeLong(baos, 4, messageId);
cert.writeBytes(baos);
DataHelper.writeDate(baos, new Date(expiration));
int paddedSize = 256; instructions.writeBytes(baos);
SessionKey sessKey = null; DataHelper.writeLong(baos, 4, messageId);
SessionTag tag = null; cert.writeBytes(baos);
if (instructions.getDelayRequested()) { DataHelper.writeDate(baos, new Date(expiration));
// always use a new key if we're delaying, since the reply block may not be used within the
// window of a session int paddedSize = 256;
sessKey = KeyGenerator.getInstance().generateSessionKey(); SessionKey sessKey = null;
tag = null; SessionTag tag = null;
_log.debug("Delay requested - creating a new session key"); if (instructions.getDelayRequested()) {
} else { // always use a new key if we're delaying, since the reply block may not be used within the
sessKey = SessionKeyManager.getInstance().getCurrentKey(replyThrough); // window of a session
if (sessKey == null) { sessKey = ctx.keyGenerator().generateSessionKey();
sessKey = KeyGenerator.getInstance().generateSessionKey(); tag = null;
tag = null; if (_log.shouldLog(Log.DEBUG))
_log.debug("No delay requested, but no session key is known"); _log.debug("Delay requested - creating a new session key");
} else { } else {
tag = SessionKeyManager.getInstance().consumeNextAvailableTag(replyThrough, sessKey); sessKey = ctx.sessionKeyManager().getCurrentKey(replyThrough);
} if (sessKey == null) {
} sessKey = ctx.keyGenerator().generateSessionKey();
byte encData[] = ElGamalAESEngine.encrypt(baos.toByteArray(), replyThrough, sessKey, null, tag, paddedSize); tag = null;
setData(encData); if (_log.shouldLog(Log.DEBUG))
} catch (IOException ioe) { _log.debug("No delay requested, but no session key is known");
throw new DataFormatException("Error writing out the source route block data", ioe); } else {
} catch (DataFormatException dfe) { tag = ctx.sessionKeyManager().consumeNextAvailableTag(replyThrough, sessKey);
throw new DataFormatException("Error writing out the source route block data", dfe); }
} }
byte encData[] = ctx.elGamalAESEngine().encrypt(baos.toByteArray(), replyThrough,
sessKey, null, tag, paddedSize);
setData(encData);
} catch (IOException ioe) {
throw new DataFormatException("Error writing out the source route block data", ioe);
} catch (DataFormatException dfe) {
throw new DataFormatException("Error writing out the source route block data", dfe);
}
} }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
_router = new Hash(); _router = new Hash();
_router.readBytes(in); _router.readBytes(in);
int size = (int)DataHelper.readLong(in, 2); int size = (int)DataHelper.readLong(in, 2);
_data = new byte[size]; _data = new byte[size];
int read = read(in, _data); int read = read(in, _data);
if (read != _data.length) if (read != _data.length)
throw new DataFormatException("Incorrect # of bytes read for source route block: " + read); throw new DataFormatException("Incorrect # of bytes read for source route block: " + read);
_key = new SessionKey(); _key = new SessionKey();
_key.readBytes(in); _key.readBytes(in);
_tag = new byte[32]; _tag = new byte[32];
read = read(in, _tag); read = read(in, _tag);
if (read != _tag.length) if (read != _tag.length)
throw new DataFormatException("Incorrect # of bytes read for session tag: " + read); throw new DataFormatException("Incorrect # of bytes read for session tag: " + read);
} }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if ( (_router == null) || (_data == null) || (_key == null) || (_tag == null) || (_tag.length != 32) ) if ( (_router == null) || (_data == null) || (_key == null) || (_tag == null) || (_tag.length != 32) )
throw new DataFormatException("Insufficient data to write"); throw new DataFormatException("Insufficient data to write");
_router.writeBytes(out); _router.writeBytes(out);
DataHelper.writeLong(out, 2, _data.length); DataHelper.writeLong(out, 2, _data.length);
out.write(_data); out.write(_data);
_key.writeBytes(out); _key.writeBytes(out);
out.write(_tag); out.write(_tag);
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof SourceRouteBlock)) if ( (obj == null) || !(obj instanceof SourceRouteBlock))
return false; return false;
SourceRouteBlock block = (SourceRouteBlock)obj; SourceRouteBlock block = (SourceRouteBlock)obj;
return DataHelper.eq(getRouter(), block.getRouter()) && return DataHelper.eq(getRouter(), block.getRouter()) &&
DataHelper.eq(getData(), block.getData()) && DataHelper.eq(getData(), block.getData()) &&
DataHelper.eq(getKey(), block.getKey()) && DataHelper.eq(getKey(), block.getKey()) &&
DataHelper.eq(getTag(), block.getTag()); DataHelper.eq(getTag(), block.getTag());
} }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getRouter()) + return DataHelper.hashCode(getRouter()) +
DataHelper.hashCode(getData()) + DataHelper.hashCode(getData()) +
DataHelper.hashCode(getKey()) + DataHelper.hashCode(getKey()) +
DataHelper.hashCode(getTag()); DataHelper.hashCode(getTag());
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append("[SourceRouteBlock: "); buf.append("[SourceRouteBlock: ");
buf.append("\n\tRouter: ").append(getRouter()); buf.append("\n\tRouter: ").append(getRouter());
buf.append("\n\tData: ").append(DataHelper.toString(getData(), getData().length)); buf.append("\n\tData: ").append(DataHelper.toString(getData(), getData().length));
buf.append("\n\tTag: ").append(DataHelper.toString(getTag(), (getTag() != null ? getTag().length : 0))); buf.append("\n\tTag: ").append(DataHelper.toString(getTag(), (getTag() != null ? getTag().length : 0)));
buf.append("\n\tKey: ").append(getKey()); buf.append("\n\tKey: ").append(getKey());
buf.append("]"); buf.append("]");
return buf.toString(); return buf.toString();
} }
} }

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,14 +36,17 @@ 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) {
_encryptedHeader = null; super(context);
_message = null; _handler = new I2NPMessageHandler(context);
_decryptedInstructions = null; _encryptedHeader = null;
_decryptedMessageId = -1; _message = null;
_decryptedCertificate = null; _decryptedInstructions = null;
_decryptedExpiration = -1; _decryptedMessageId = -1;
_decryptedCertificate = null;
_decryptedExpiration = -1;
} }
/** /**
@ -77,54 +81,56 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl {
* @throws DataFormatException if the decryption fails or if the data is somehow malformed * @throws DataFormatException if the decryption fails or if the data is somehow malformed
*/ */
public void decryptHeader(PrivateKey key) throws DataFormatException { public void decryptHeader(PrivateKey key) throws DataFormatException {
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);
if (decr == null)
throw new DataFormatException("Decrypted data is null");
try {
ByteArrayInputStream bais = new ByteArrayInputStream(decr);
_decryptedInstructions = new DeliveryInstructions();
_decryptedInstructions.readBytes(bais);
_decryptedMessageId = DataHelper.readLong(bais, 4);
_decryptedCertificate = new Certificate();
_decryptedCertificate.readBytes(bais);
_decryptedExpiration = DataHelper.readDate(bais).getTime();
} catch (IOException ioe) { byte decr[] = _context.elGamalAESEngine().decrypt(_encryptedHeader, key);
throw new DataFormatException("Error reading the source route reply header", ioe);
} catch (DataFormatException dfe) { if (decr == null)
throw new DataFormatException("Error reading the source route reply header", dfe); throw new DataFormatException("Decrypted data is null");
}
try {
ByteArrayInputStream bais = new ByteArrayInputStream(decr);
_decryptedInstructions = new DeliveryInstructions();
_decryptedInstructions.readBytes(bais);
_decryptedMessageId = DataHelper.readLong(bais, 4);
_decryptedCertificate = new Certificate();
_decryptedCertificate.readBytes(bais);
_decryptedExpiration = DataHelper.readDate(bais).getTime();
} catch (IOException ioe) {
throw new DataFormatException("Error reading the source route reply header", ioe);
} catch (DataFormatException dfe) {
throw new DataFormatException("Error reading the source route reply header", dfe);
}
} }
public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { 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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_encryptedHeader == null) || (_message == null) ) if ( (_encryptedHeader == null) || (_message == null) )
throw new I2NPMessageException("Not enough data to write out"); throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(1024); ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
try { try {
DataHelper.writeLong(os, 2, _encryptedHeader.length); DataHelper.writeLong(os, 2, _encryptedHeader.length);
os.write(_encryptedHeader); os.write(_encryptedHeader);
_message.writeBytes(os); _message.writeBytes(os);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -134,15 +140,15 @@ public class SourceRouteReplyMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(_encryptedHeader) + return DataHelper.hashCode(_encryptedHeader) +
DataHelper.hashCode(_message); DataHelper.hashCode(_message);
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof SourceRouteReplyMessage) ) { if ( (object != null) && (object instanceof SourceRouteReplyMessage) ) {
SourceRouteReplyMessage msg = (SourceRouteReplyMessage)object; SourceRouteReplyMessage msg = (SourceRouteReplyMessage)object;
return DataHelper.eq(_message,msg._message) && return DataHelper.eq(_message,msg._message) &&
DataHelper.eq(_encryptedHeader,msg._encryptedHeader); DataHelper.eq(_encryptedHeader,msg._encryptedHeader);
} else { } else {
return false; return false;
} }

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -18,6 +18,7 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.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,23 +53,24 @@ 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) {
setParticipantType(-1); super(context);
setNextRouter(null); setParticipantType(-1);
setTunnelId(null); setNextRouter(null);
setTunnelDurationSeconds(-1); setTunnelId(null);
setConfigurationKey(null); setTunnelDurationSeconds(-1);
setMaxPeakMessagesPerMin(-1); setConfigurationKey(null);
setMaxAvgMessagesPerMin(-1); setMaxPeakMessagesPerMin(-1);
setMaxPeakBytesPerMin(-1); setMaxAvgMessagesPerMin(-1);
setMaxAvgBytesPerMin(-1); setMaxPeakBytesPerMin(-1);
setIncludeDummyTraffic(false); setMaxAvgBytesPerMin(-1);
setReorderMessages(false); setIncludeDummyTraffic(false);
setVerificationPublicKey(null); setReorderMessages(false);
setVerificationPrivateKey(null); setVerificationPublicKey(null);
setTunnelKey(null); setVerificationPrivateKey(null);
setCertificate(null); setTunnelKey(null);
setReplyBlock(null); setCertificate(null);
setReplyBlock(null);
} }
public void setParticipantType(int type) { _participantType = type; } public void setParticipantType(int type) { _participantType = type; }
@ -105,41 +107,41 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
public SourceRouteBlock getReplyBlock() { return _replyBlock; } public SourceRouteBlock getReplyBlock() { return _replyBlock; }
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 {
_participantType = (int)DataHelper.readLong(in, 1); _participantType = (int)DataHelper.readLong(in, 1);
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
_nextRouter = new Hash(); _nextRouter = new Hash();
_nextRouter.readBytes(in); _nextRouter.readBytes(in);
} }
_tunnelId = new TunnelId(); _tunnelId = new TunnelId();
_tunnelId.readBytes(in); _tunnelId.readBytes(in);
_tunnelDuration = DataHelper.readLong(in, 4); _tunnelDuration = DataHelper.readLong(in, 4);
_configKey = new TunnelConfigurationSessionKey(); _configKey = new TunnelConfigurationSessionKey();
_configKey.readBytes(in); _configKey.readBytes(in);
_maxPeakMessagesPerMin = DataHelper.readLong(in, 4); _maxPeakMessagesPerMin = DataHelper.readLong(in, 4);
_maxAvgMessagesPerMin = DataHelper.readLong(in, 4); _maxAvgMessagesPerMin = DataHelper.readLong(in, 4);
_maxPeakBytesPerMin = DataHelper.readLong(in, 4); _maxPeakBytesPerMin = DataHelper.readLong(in, 4);
_maxAvgBytesPerMin = DataHelper.readLong(in, 4); _maxAvgBytesPerMin = DataHelper.readLong(in, 4);
int flags = (int)DataHelper.readLong(in, 1); int flags = (int)DataHelper.readLong(in, 1);
_includeDummyTraffic = flagsIncludeDummy(flags); _includeDummyTraffic = flagsIncludeDummy(flags);
_reorderMessages = flagsReorder(flags); _reorderMessages = flagsReorder(flags);
_verificationPubKey = new TunnelSigningPublicKey(); _verificationPubKey = new TunnelSigningPublicKey();
_verificationPubKey.readBytes(in); _verificationPubKey.readBytes(in);
if (_participantType == PARTICIPANT_TYPE_GATEWAY) { if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
_verificationPrivKey = new TunnelSigningPrivateKey(); _verificationPrivKey = new TunnelSigningPrivateKey();
_verificationPrivKey.readBytes(in); _verificationPrivKey.readBytes(in);
} }
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
_tunnelKey = new TunnelSessionKey(); _tunnelKey = new TunnelSessionKey();
_tunnelKey.readBytes(in); _tunnelKey.readBytes(in);
} }
_certificate = new Certificate(); _certificate = new Certificate();
_certificate.readBytes(in); _certificate.readBytes(in);
_replyBlock = new SourceRouteBlock(); _replyBlock = new SourceRouteBlock();
_replyBlock.readBytes(in); _replyBlock.readBytes(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);
} }
@ -148,146 +150,99 @@ public class TunnelCreateMessage extends I2NPMessageImpl {
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
DataHelper.writeLong(os, 1, _participantType); DataHelper.writeLong(os, 1, _participantType);
if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { if (_participantType != PARTICIPANT_TYPE_ENDPOINT) {
_nextRouter.writeBytes(os); _nextRouter.writeBytes(os);
} }
_tunnelId.writeBytes(os); _tunnelId.writeBytes(os);
DataHelper.writeLong(os, 4, _tunnelDuration); DataHelper.writeLong(os, 4, _tunnelDuration);
_configKey.writeBytes(os); _configKey.writeBytes(os);
DataHelper.writeLong(os, 4, _maxPeakMessagesPerMin); DataHelper.writeLong(os, 4, _maxPeakMessagesPerMin);
DataHelper.writeLong(os, 4, _maxAvgMessagesPerMin); DataHelper.writeLong(os, 4, _maxAvgMessagesPerMin);
DataHelper.writeLong(os, 4, _maxPeakBytesPerMin); DataHelper.writeLong(os, 4, _maxPeakBytesPerMin);
DataHelper.writeLong(os, 4, _maxAvgBytesPerMin); DataHelper.writeLong(os, 4, _maxAvgBytesPerMin);
long flags = getFlags(); long flags = getFlags();
DataHelper.writeLong(os, 1, flags); DataHelper.writeLong(os, 1, flags);
_verificationPubKey.writeBytes(os); _verificationPubKey.writeBytes(os);
if (_participantType == PARTICIPANT_TYPE_GATEWAY) { if (_participantType == PARTICIPANT_TYPE_GATEWAY) {
_verificationPrivKey.writeBytes(os); _verificationPrivKey.writeBytes(os);
} }
if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) {
_tunnelKey.writeBytes(os); _tunnelKey.writeBytes(os);
} }
_certificate.writeBytes(os); _certificate.writeBytes(os);
_replyBlock.writeBytes(os); _replyBlock.writeBytes(os);
} 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();
} }
private boolean flagsIncludeDummy(long flags) { private boolean flagsIncludeDummy(long flags) {
return (0 != (flags & FLAG_DUMMY)); return (0 != (flags & FLAG_DUMMY));
} }
private boolean flagsReorder(long flags) { private boolean flagsReorder(long flags) {
return (0 != (flags & FLAG_REORDER)); return (0 != (flags & FLAG_REORDER));
} }
private long getFlags() { private long getFlags() {
long val = 0L; long val = 0L;
if (getIncludeDummyTraffic()) if (getIncludeDummyTraffic())
val = val | FLAG_DUMMY; val = val | FLAG_DUMMY;
if (getReorderMessages()) if (getReorderMessages())
val = val | FLAG_REORDER; val = val | FLAG_REORDER;
return val; return val;
} }
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return (int)(DataHelper.hashCode(getCertificate()) + return (int)(DataHelper.hashCode(getCertificate()) +
DataHelper.hashCode(getConfigurationKey()) + DataHelper.hashCode(getConfigurationKey()) +
DataHelper.hashCode(getNextRouter()) + DataHelper.hashCode(getNextRouter()) +
DataHelper.hashCode(getReplyBlock()) + DataHelper.hashCode(getReplyBlock()) +
DataHelper.hashCode(getTunnelId()) + DataHelper.hashCode(getTunnelId()) +
DataHelper.hashCode(getTunnelKey()) + DataHelper.hashCode(getTunnelKey()) +
DataHelper.hashCode(getVerificationPrivateKey()) + DataHelper.hashCode(getVerificationPrivateKey()) +
DataHelper.hashCode(getVerificationPublicKey()) + DataHelper.hashCode(getVerificationPublicKey()) +
(getIncludeDummyTraffic() ? 1 : 0) + (getIncludeDummyTraffic() ? 1 : 0) +
getMaxAvgBytesPerMin() + getMaxAvgBytesPerMin() +
getMaxAvgMessagesPerMin() + getMaxAvgMessagesPerMin() +
getMaxPeakBytesPerMin() + getMaxPeakBytesPerMin() +
getMaxPeakMessagesPerMin() + getMaxPeakMessagesPerMin() +
getParticipantType() + getParticipantType() +
(getReorderMessages() ? 1 : 0) + (getReorderMessages() ? 1 : 0) +
getTunnelDurationSeconds()); getTunnelDurationSeconds());
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof TunnelCreateMessage) ) { if ( (object != null) && (object instanceof TunnelCreateMessage) ) {
TunnelCreateMessage msg = (TunnelCreateMessage)object; TunnelCreateMessage msg = (TunnelCreateMessage)object;
return DataHelper.eq(getCertificate(), msg.getCertificate()) && return DataHelper.eq(getCertificate(), msg.getCertificate()) &&
DataHelper.eq(getConfigurationKey(), msg.getConfigurationKey()) && DataHelper.eq(getConfigurationKey(), msg.getConfigurationKey()) &&
DataHelper.eq(getNextRouter(), msg.getNextRouter()) && DataHelper.eq(getNextRouter(), msg.getNextRouter()) &&
DataHelper.eq(getReplyBlock(), msg.getReplyBlock()) && DataHelper.eq(getReplyBlock(), msg.getReplyBlock()) &&
DataHelper.eq(getTunnelId(), msg.getTunnelId()) && DataHelper.eq(getTunnelId(), msg.getTunnelId()) &&
DataHelper.eq(getTunnelKey(), msg.getTunnelKey()) && DataHelper.eq(getTunnelKey(), msg.getTunnelKey()) &&
DataHelper.eq(getVerificationPrivateKey(), msg.getVerificationPrivateKey()) && DataHelper.eq(getVerificationPrivateKey(), msg.getVerificationPrivateKey()) &&
DataHelper.eq(getVerificationPublicKey(), msg.getVerificationPublicKey()) && DataHelper.eq(getVerificationPublicKey(), msg.getVerificationPublicKey()) &&
(getIncludeDummyTraffic() == msg.getIncludeDummyTraffic()) && (getIncludeDummyTraffic() == msg.getIncludeDummyTraffic()) &&
(getMaxAvgBytesPerMin() == msg.getMaxAvgBytesPerMin()) && (getMaxAvgBytesPerMin() == msg.getMaxAvgBytesPerMin()) &&
(getMaxAvgMessagesPerMin() == msg.getMaxAvgMessagesPerMin()) && (getMaxAvgMessagesPerMin() == msg.getMaxAvgMessagesPerMin()) &&
(getMaxPeakBytesPerMin() == msg.getMaxPeakBytesPerMin()) && (getMaxPeakBytesPerMin() == msg.getMaxPeakBytesPerMin()) &&
(getMaxPeakMessagesPerMin() == msg.getMaxPeakMessagesPerMin()) && (getMaxPeakMessagesPerMin() == msg.getMaxPeakMessagesPerMin()) &&
(getParticipantType() == msg.getParticipantType()) && (getParticipantType() == msg.getParticipantType()) &&
(getReorderMessages() == msg.getReorderMessages()) && (getReorderMessages() == msg.getReorderMessages()) &&
(getTunnelDurationSeconds() == msg.getTunnelDurationSeconds()); (getTunnelDurationSeconds() == msg.getTunnelDurationSeconds());
} else { } else {
return false; return false;
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[TunnelCreateMessage: "); buf.append("[TunnelCreateMessage: ");
buf.append("\n\tParticipant Type: ").append(getParticipantType()); buf.append("\n\tParticipant Type: ").append(getParticipantType());

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -17,9 +17,10 @@ import net.i2p.data.DataHelper;
import net.i2p.data.Hash; import net.i2p.data.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
* TunnelCreateMessage * TunnelCreateMessage
* *
* @author jrandom * @author jrandom
@ -37,10 +38,11 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl {
public final static int STATUS_FAILED_CERTIFICATE = 3; public final static int STATUS_FAILED_CERTIFICATE = 3;
public final static int STATUS_FAILED_DELETED = 100; public final static int STATUS_FAILED_DELETED = 100;
public TunnelCreateStatusMessage() { public TunnelCreateStatusMessage(I2PAppContext context) {
setTunnelId(null); super(context);
setStatus(-1); setTunnelId(null);
setFromHash(null); setStatus(-1);
setFromHash(null);
} }
public TunnelId getTunnelId() { return _tunnelId; } public TunnelId getTunnelId() { return _tunnelId; }
@ -56,26 +58,26 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl {
public void setFromHash(Hash from) { _from = from; } public void setFromHash(Hash from) { _from = from; }
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 {
_tunnelId = new TunnelId(); _tunnelId = new TunnelId();
_tunnelId.readBytes(in); _tunnelId.readBytes(in);
_status = (int)DataHelper.readLong(in, 1); _status = (int)DataHelper.readLong(in, 1);
_from = new Hash(); _from = new Hash();
_from.readBytes(in); _from.readBytes(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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out"); if ( (_tunnelId == null) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
_tunnelId.writeBytes(os); _tunnelId.writeBytes(os);
DataHelper.writeLong(os, 1, (_status < 0 ? 255 : _status)); DataHelper.writeLong(os, 1, (_status < 0 ? 255 : _status));
_from.writeBytes(os); _from.writeBytes(os);
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
@ -85,23 +87,23 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl {
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getTunnelId()) + return DataHelper.hashCode(getTunnelId()) +
getStatus() + getStatus() +
DataHelper.hashCode(getFromHash()); DataHelper.hashCode(getFromHash());
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof TunnelCreateStatusMessage) ) { if ( (object != null) && (object instanceof TunnelCreateStatusMessage) ) {
TunnelCreateStatusMessage msg = (TunnelCreateStatusMessage)object; TunnelCreateStatusMessage msg = (TunnelCreateStatusMessage)object;
return DataHelper.eq(getTunnelId(),msg.getTunnelId()) && return DataHelper.eq(getTunnelId(),msg.getTunnelId()) &&
DataHelper.eq(getFromHash(),msg.getFromHash()) && DataHelper.eq(getFromHash(),msg.getFromHash()) &&
(getStatus() == msg.getStatus()); (getStatus() == msg.getStatus());
} else { } else {
return false; return false;
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[TunnelCreateStatusMessage: "); buf.append("[TunnelCreateStatusMessage: ");
buf.append("\n\tTunnel ID: ").append(getTunnelId()); buf.append("\n\tTunnel ID: ").append(getTunnelId());

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -16,6 +16,7 @@ import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper; import net.i2p.data.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,11 +35,12 @@ 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) {
setTunnelId(null); super(context);
setData(null); setTunnelId(null);
setVerificationStructure(null); setData(null);
setEncryptedDeliveryInstructions(null); setVerificationStructure(null);
setEncryptedDeliveryInstructions(null);
} }
public TunnelId getTunnelId() { return _tunnelId; } public TunnelId getTunnelId() { return _tunnelId; }
@ -54,85 +56,85 @@ public class TunnelMessage extends I2NPMessageImpl {
public void setEncryptedDeliveryInstructions(byte instructions[]) { _encryptedInstructions = instructions; } public void setEncryptedDeliveryInstructions(byte instructions[]) { _encryptedInstructions = instructions; }
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 {
_tunnelId = new TunnelId(); _tunnelId = new TunnelId();
_tunnelId.readBytes(in); _tunnelId.readBytes(in);
_log.debug("Read tunnel message for tunnel " + _tunnelId); _log.debug("Read tunnel message for tunnel " + _tunnelId);
_size = DataHelper.readLong(in, 4); _size = DataHelper.readLong(in, 4);
_log.debug("Read tunnel message size: " + _size); _log.debug("Read tunnel message size: " + _size);
if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size); if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size);
_data = new byte[(int)_size]; _data = new byte[(int)_size];
int read = read(in, _data); int read = read(in, _data);
if (read != _size) if (read != _size)
throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size); throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size);
int includeVerification = (int)DataHelper.readLong(in, 1); int includeVerification = (int)DataHelper.readLong(in, 1);
if (includeVerification == FLAG_INCLUDESTRUCTURE) { if (includeVerification == FLAG_INCLUDESTRUCTURE) {
_verification = new TunnelVerificationStructure(); _verification = new TunnelVerificationStructure();
_verification.readBytes(in); _verification.readBytes(in);
int len = (int)DataHelper.readLong(in, 2); int len = (int)DataHelper.readLong(in, 2);
_encryptedInstructions = new byte[len]; _encryptedInstructions = new byte[len];
read = read(in, _encryptedInstructions); read = read(in, _encryptedInstructions);
if (read != len) if (read != len)
throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")"); throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")");
} }
} 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);
} }
} }
protected byte[] writeMessage() throws I2NPMessageException, IOException { protected byte[] writeMessage() throws I2NPMessageException, IOException {
if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) ) if ( (_tunnelId == null) || (_data == null) || (_data.length <= 0) )
throw new I2NPMessageException("Not enough data to write out"); throw new I2NPMessageException("Not enough data to write out");
ByteArrayOutputStream os = new ByteArrayOutputStream(32); ByteArrayOutputStream os = new ByteArrayOutputStream(32);
try { try {
_tunnelId.writeBytes(os); _tunnelId.writeBytes(os);
_log.debug("Writing tunnel message for tunnel " + _tunnelId); _log.debug("Writing tunnel message for tunnel " + _tunnelId);
DataHelper.writeLong(os, 4, _data.length); DataHelper.writeLong(os, 4, _data.length);
_log.debug("Writing tunnel message length: " + _data.length); _log.debug("Writing tunnel message length: " + _data.length);
os.write(_data); os.write(_data);
_log.debug("Writing tunnel message data"); _log.debug("Writing tunnel message data");
if ( (_verification == null) || (_encryptedInstructions == null) ) { if ( (_verification == null) || (_encryptedInstructions == null) ) {
DataHelper.writeLong(os, 1, FLAG_DONT_INCLUDESTRUCTURE); DataHelper.writeLong(os, 1, FLAG_DONT_INCLUDESTRUCTURE);
_log.debug("Writing DontIncludeStructure flag"); _log.debug("Writing DontIncludeStructure flag");
} else { } else {
DataHelper.writeLong(os, 1, FLAG_INCLUDESTRUCTURE); DataHelper.writeLong(os, 1, FLAG_INCLUDESTRUCTURE);
_log.debug("Writing IncludeStructure flag, then the verification structure, then the E(instr).length [" + _encryptedInstructions.length + "], then the E(instr)"); _log.debug("Writing IncludeStructure flag, then the verification structure, then the E(instr).length [" + _encryptedInstructions.length + "], then the E(instr)");
_verification.writeBytes(os); _verification.writeBytes(os);
DataHelper.writeLong(os, 2, _encryptedInstructions.length); DataHelper.writeLong(os, 2, _encryptedInstructions.length);
os.write(_encryptedInstructions); os.write(_encryptedInstructions);
} }
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
throw new I2NPMessageException("Error writing out the message data", dfe); throw new I2NPMessageException("Error writing out the message data", dfe);
} }
byte rv[] = os.toByteArray(); byte rv[] = os.toByteArray();
_log.debug("Overall data being written: " + rv.length); _log.debug("Overall data being written: " + rv.length);
return rv; return rv;
} }
public int getType() { return MESSAGE_TYPE; } public int getType() { return MESSAGE_TYPE; }
public int hashCode() { public int hashCode() {
return DataHelper.hashCode(getTunnelId()) + return DataHelper.hashCode(getTunnelId()) +
DataHelper.hashCode(_data) + DataHelper.hashCode(_data) +
DataHelper.hashCode(getVerificationStructure()) + DataHelper.hashCode(getVerificationStructure()) +
DataHelper.hashCode(getEncryptedDeliveryInstructions()); DataHelper.hashCode(getEncryptedDeliveryInstructions());
} }
public boolean equals(Object object) { public boolean equals(Object object) {
if ( (object != null) && (object instanceof TunnelMessage) ) { if ( (object != null) && (object instanceof TunnelMessage) ) {
TunnelMessage msg = (TunnelMessage)object; TunnelMessage msg = (TunnelMessage)object;
return DataHelper.eq(getTunnelId(),msg.getTunnelId()) && return DataHelper.eq(getTunnelId(),msg.getTunnelId()) &&
DataHelper.eq(getVerificationStructure(),msg.getVerificationStructure()) && DataHelper.eq(getVerificationStructure(),msg.getVerificationStructure()) &&
DataHelper.eq(getData(),msg.getData()) && DataHelper.eq(getData(),msg.getData()) &&
DataHelper.eq(getEncryptedDeliveryInstructions(), msg.getEncryptedDeliveryInstructions()); DataHelper.eq(getEncryptedDeliveryInstructions(), msg.getEncryptedDeliveryInstructions());
} else { } else {
return false; return false;
} }
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[TunnelMessage: "); buf.append("[TunnelMessage: ");
buf.append("\n\tTunnel ID: ").append(getTunnelId()); buf.append("\n\tTunnel ID: ").append(getTunnelId());

View File

@ -1,9 +1,9 @@
package net.i2p.data.i2np; package net.i2p.data.i2np;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -21,19 +21,19 @@ import net.i2p.data.Signature;
import net.i2p.data.SigningPrivateKey; import net.i2p.data.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;
public TunnelVerificationStructure() { public TunnelVerificationStructure() {
setMessageHash(null); setMessageHash(null);
setAuthorizationSignature(null); setAuthorizationSignature(null);
} }
public Hash getMessageHash() { return _msgHash; } public Hash getMessageHash() { return _msgHash; }
@ -42,45 +42,45 @@ 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 {
_msgHash = new Hash(); _msgHash = new Hash();
_msgHash.readBytes(in); _msgHash.readBytes(in);
_authSignature = new Signature(); _authSignature = new Signature();
_authSignature.readBytes(in); _authSignature.readBytes(in);
} }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_authSignature == null) { if (_authSignature == null) {
_authSignature = new Signature(); _authSignature = new Signature();
_authSignature.setData(Signature.FAKE_SIGNATURE); _authSignature.setData(Signature.FAKE_SIGNATURE);
} }
if ( (_msgHash == null) || (_authSignature == null) ) throw new DataFormatException("Invalid data"); if ( (_msgHash == null) || (_authSignature == null) ) throw new DataFormatException("Invalid data");
_msgHash.writeBytes(out); _msgHash.writeBytes(out);
_authSignature.writeBytes(out); _authSignature.writeBytes(out);
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( (obj == null) || !(obj instanceof TunnelVerificationStructure)) if ( (obj == null) || !(obj instanceof TunnelVerificationStructure))
return false; return false;
TunnelVerificationStructure str = (TunnelVerificationStructure)obj; TunnelVerificationStructure str = (TunnelVerificationStructure)obj;
return DataHelper.eq(getMessageHash(), str.getMessageHash()) && return DataHelper.eq(getMessageHash(), str.getMessageHash()) &&
DataHelper.eq(getAuthorizationSignature(), str.getAuthorizationSignature()); DataHelper.eq(getAuthorizationSignature(), str.getAuthorizationSignature());
} }
public int hashCode() { public int hashCode() {
if ( (_msgHash == null) || (_authSignature == null) ) return 0; if ( (_msgHash == null) || (_authSignature == null) ) return 0;
return getMessageHash().hashCode() + getAuthorizationSignature().hashCode(); return getMessageHash().hashCode() + getAuthorizationSignature().hashCode();
} }
public String toString() { public String toString() {

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() { public void startup() {}
//JobQueue.getInstance().addJob(new PollOutboundClientMessagesJob());
}
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) { } else {
// _inMessages.add(msg); _log.debug("Adding message for remote delivery");
//} _context.jobQueue().addJob(new OutboundClientMessageJob(_context, msg));
} else { }
_log.debug("Adding message for remote delivery");
//JobQueue.getInstance().addJob(new ProcessOutboundClientMessageJob(msg));
JobQueue.getInstance().addJob(new OutboundClientMessageJob(msg));
//synchronized (_outMessages) {
// _outMessages.add(msg);
//}
}
}
/**
* Retrieve the next locally destined message, or null if none are available.
*
*/
public ClientMessage getNextLocal() {
synchronized (_inMessages) {
if (_inMessages.size() <= 0) return null;
return (ClientMessage)_inMessages.remove(0);
}
}
/**
* Retrieve the next remotely destined message, or null if none are available.
*
*/
public ClientMessage getNextRemote() {
synchronized (_outMessages) {
if (_outMessages.size() <= 0) return null;
return (ClientMessage)_outMessages.remove(0);
}
}
/**
* Determine how many locally bound messages are in the pool
*
*/
public int getLocalCount() {
synchronized (_inMessages) {
return _inMessages.size();
}
}
/**
* Determine how many remotely bound messages are in the pool.
*
*/
public int getRemoteCount() {
synchronized (_outMessages) {
return _outMessages.size();
}
}
public void dumpPoolInfo() {
StringBuffer buf = new StringBuffer();
buf.append("\nDumping Client Message Pool. Local messages: ").append(getLocalCount()).append(" Remote messages: ").append(getRemoteCount()).append("\n");
buf.append("Inbound messages\n");
buf.append("----------------------------\n");
synchronized (_inMessages) {
for (Iterator iter = _inMessages.iterator(); iter.hasNext();) {
ClientMessage msg = (ClientMessage)iter.next();
buf.append(msg).append("\n\n");
}
}
buf.append("Outbound messages\n");
buf.append("----------------------------\n");
synchronized (_outMessages) {
for (Iterator iter = _outMessages.iterator(); iter.hasNext();) {
ClientMessage msg = (ClientMessage)iter.next();
buf.append(msg).append("\n\n");
}
}
_log.debug(buf.toString());
} }
} }

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,24 +121,24 @@ 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;
} }
} }
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,40 +13,42 @@ 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;
_id = ++_idSrc; _timing = new JobTiming(context);
_addedBy = null; _id = ++_idSrc;
_madeReadyOn = 0; _addedBy = null;
_madeReadyOn = 0;
} }
public int getJobId() { return _id; } public int getJobId() { return _id; }
public JobTiming getTiming() { return _timing; } public JobTiming getTiming() { return _timing; }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(super.toString()); buf.append(super.toString());
buf.append(": Job ").append(_id).append(": ").append(getName()); buf.append(": Job ").append(_id).append(": ").append(getName());
return buf.toString(); return buf.toString();
} }
void addedToQueue() { void addedToQueue() {
_addedBy = new Exception(); _addedBy = new Exception();
} }
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);
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -6,103 +6,105 @@ 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 }); _id = id;
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 }); _keepRunning = true;
StatManager.getInstance().createRateStat("jobQueue.jobRunnerInactive", "How long are runners inactive?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); _numJobs = 0;
_currentJob = null;
_log = _context.logManager().getLog(JobQueueRunner.class);
_context.statManager().createRateStat("jobQueue.jobRun", "How long jobs take", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
_context.statManager().createRateStat("jobQueue.jobLag", "How long jobs have to wait before running", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
_context.statManager().createRateStat("jobQueue.jobWait", "How long does a job sat on the job queue?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
_context.statManager().createRateStat("jobQueue.jobRunnerInactive", "How long are runners inactive?", "JobQueue", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l });
} }
public JobQueueRunner(int id) {
_id = id;
_keepRunning = true;
_numJobs = 0;
_currentJob = null;
}
public Job getCurrentJob() { return _currentJob; } public 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;
if (job instanceof JobImpl) {
long when = ((JobImpl)job).getMadeReadyOn();
if (when <= 0) {
_log.error("Job was not made ready?! " + job, new Exception("Not made ready?!"));
} else {
enqueuedTime = now - when;
}
}
long betweenJobs = now - lastActive;
StatManager.getInstance().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs);
_currentJob = job;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName());
long origStartAfter = job.getTiming().getStartAfter();
long doStart = Clock.getInstance().now();
job.getTiming().start();
runCurrentJob();
job.getTiming().end();
long duration = job.getTiming().getActualEnd() - job.getTiming().getActualStart();
long beforeUpdate = Clock.getInstance().now(); long enqueuedTime = 0;
JobQueue.getInstance().updateStats(job, doStart, origStartAfter, duration); if (job instanceof JobImpl) {
long diff = Clock.getInstance().now() - beforeUpdate; long when = ((JobImpl)job).getMadeReadyOn();
if (when <= 0) {
StatManager.getInstance().addRateData("jobQueue.jobRun", duration, duration); _log.error("Job was not made ready?! " + job,
StatManager.getInstance().addRateData("jobQueue.jobLag", doStart - origStartAfter, 0); new Exception("Not made ready?!"));
StatManager.getInstance().addRateData("jobQueue.jobWait", enqueuedTime, enqueuedTime); } else {
enqueuedTime = now - when;
if (diff > 100) { }
if (_log.shouldLog(Log.WARN)) }
_log.warn("Updating statistics for the job took too long [" + diff + "ms]");
} long betweenJobs = now - lastActive;
if (_log.shouldLog(Log.DEBUG)) _context.statManager().addRateData("jobQueue.jobRunnerInactive", betweenJobs, betweenJobs);
_log.debug("Job duration " + duration + "ms for " + job.getName() + " with lag of " + (doStart-origStartAfter) + "ms"); _currentJob = job;
lastActive = Clock.getInstance().now(); if (_log.shouldLog(Log.DEBUG))
_currentJob = null; _log.debug("Runner " + _id + " running job " + job.getJobId() + ": " + job.getName());
} catch (Throwable t) { long origStartAfter = job.getTiming().getStartAfter();
if (_log.shouldLog(Log.CRIT)) long doStart = _context.clock().now();
_log.log(Log.CRIT, "WTF, error running?", t); job.getTiming().start();
} runCurrentJob();
} job.getTiming().end();
if (_log.shouldLog(Log.CRIT)) long duration = job.getTiming().getActualEnd() - job.getTiming().getActualStart();
_log.log(Log.CRIT, "Queue runner " + _id + " exiting"); long beforeUpdate = _context.clock().now();
JobQueue.getInstance().removeRunner(_id); _context.jobQueue().updateStats(job, doStart, origStartAfter, duration);
long diff = _context.clock().now() - beforeUpdate;
_context.statManager().addRateData("jobQueue.jobRun", duration, duration);
_context.statManager().addRateData("jobQueue.jobLag", doStart - origStartAfter, 0);
_context.statManager().addRateData("jobQueue.jobWait", enqueuedTime, enqueuedTime);
if (diff > 100) {
if (_log.shouldLog(Log.WARN))
_log.warn("Updating statistics for the job took too long [" + diff + "ms]");
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Job duration " + duration + "ms for " + job.getName()
+ " with lag of " + (doStart-origStartAfter) + "ms");
lastActive = _context.clock().now();
_currentJob = null;
} catch (Throwable t) {
if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "WTF, error running?", t);
}
}
if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, "Queue runner " + _id + " exiting");
_context.jobQueue().removeRunner(_id);
} }
private void runCurrentJob() { private void runCurrentJob() {
try { try {
_currentJob.runJob(); _currentJob.runJob();
} catch (OutOfMemoryError oom) { } catch (OutOfMemoryError oom) {
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");
} }
try { Thread.sleep(1000); } catch (InterruptedException ie) {} try { Thread.sleep(1000); } catch (InterruptedException ie) {}
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()
if (_log.shouldLog(Log.ERROR)) + "] on thread " + _id + ": " + t.getMessage(), t);
_log.error("The above job was enqueued by: ", _currentJob.getAddedBy()); if (_log.shouldLog(Log.ERROR))
JobQueue.getInstance().dumpRunners(true); _log.error("The above job was enqueued by: ", _currentJob.getAddedBy());
} }
} }
} }

View File

@ -1,14 +1,15 @@
package net.i2p.router; package net.i2p.router;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
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;
_actualStart = 0; _start = context.clock().now();
_actualEnd = 0; _actualStart = 0;
Clock.getInstance().addUpdateListener(this); _actualEnd = 0;
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
* *
@ -53,17 +56,17 @@ public class JobTiming implements Clock.ClockUpdateListener {
* Notify the timing that the job finished * Notify the timing that the job finished
* *
*/ */
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) {
if (_start != 0) if (_start != 0)
_start += delta; _start += delta;
if (_actualStart != 0) if (_actualStart != 0)
_actualStart += delta; _actualStart += delta;
if (_actualEnd != 0) if (_actualEnd != 0)
_actualEnd += delta; _actualEnd += 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) {
setPrivateKey(null); _context = context;
setPublicKey(null); _log = _context.logManager().getLog(KeyManager.class);
setSigningPrivateKey(null); setPrivateKey(null);
setSigningPublicKey(null); setPublicKey(null);
_leaseSetKeys = new HashMap(); setSigningPrivateKey(null);
JobQueue.getInstance().addJob(new SynchronizeKeysJob()); setSigningPublicKey(null);
_leaseSetKeys = new HashMap();
_context.jobQueue().addJob(new SynchronizeKeysJob());
} }
/** Configure the router's private key */ /** Configure the router's private key */
@ -72,119 +73,122 @@ public class KeyManager {
public SigningPublicKey getSigningPublicKey() { return _signingPublicKey; } public SigningPublicKey getSigningPublicKey() { return _signingPublicKey; }
public void registerKeys(Destination dest, SigningPrivateKey leaseRevocationPrivateKey, PrivateKey endpointDecryptionKey) { public void registerKeys(Destination dest, SigningPrivateKey leaseRevocationPrivateKey, PrivateKey endpointDecryptionKey) {
_log.info("Registering keys for destination " + dest.calculateHash().toBase64()); _log.info("Registering keys for destination " + dest.calculateHash().toBase64());
LeaseSetKeys keys = new LeaseSetKeys(dest, leaseRevocationPrivateKey, endpointDecryptionKey); LeaseSetKeys keys = new LeaseSetKeys(dest, leaseRevocationPrivateKey, endpointDecryptionKey);
synchronized (_leaseSetKeys) { synchronized (_leaseSetKeys) {
_leaseSetKeys.put(dest, keys); _leaseSetKeys.put(dest, keys);
} }
} }
public LeaseSetKeys unregisterKeys(Destination dest) { public LeaseSetKeys unregisterKeys(Destination dest) {
_log.info("Unregistering keys for destination " + dest.calculateHash().toBase64()); _log.info("Unregistering keys for destination " + dest.calculateHash().toBase64());
synchronized (_leaseSetKeys) { synchronized (_leaseSetKeys) {
return (LeaseSetKeys)_leaseSetKeys.remove(dest); return (LeaseSetKeys)_leaseSetKeys.remove(dest);
} }
} }
public LeaseSetKeys getKeys(Destination dest) { public LeaseSetKeys getKeys(Destination dest) {
synchronized (_leaseSetKeys) { synchronized (_leaseSetKeys) {
return (LeaseSetKeys)_leaseSetKeys.get(dest); return (LeaseSetKeys)_leaseSetKeys.get(dest);
} }
} }
public Set getAllKeys() { public Set getAllKeys() {
HashSet keys = new HashSet(); HashSet keys = new HashSet();
synchronized (_leaseSetKeys) { synchronized (_leaseSetKeys) {
keys.addAll(_leaseSetKeys.values()); keys.addAll(_leaseSetKeys.values());
} }
return keys; return keys;
} }
private class SynchronizeKeysJob extends JobImpl { private class SynchronizeKeysJob extends JobImpl {
public void runJob() { public SynchronizeKeysJob() {
String keyDir = Router.getInstance().getConfigSetting(PROP_KEYDIR); super(KeyManager.this._context);
if (keyDir == null) }
keyDir = DEFAULT_KEYDIR; public void runJob() {
File dir = new File(keyDir); String keyDir = KeyManager.this._context.router().getConfigSetting(PROP_KEYDIR);
if (!dir.exists()) if (keyDir == null)
dir.mkdirs(); keyDir = DEFAULT_KEYDIR;
if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite()) File dir = new File(keyDir);
syncKeys(dir); if (!dir.exists())
dir.mkdirs();
getTiming().setStartAfter(Clock.getInstance().now()+DELAY); if (dir.exists() && dir.isDirectory() && dir.canRead() && dir.canWrite())
JobQueue.getInstance().addJob(this); syncKeys(dir);
}
getTiming().setStartAfter(KeyManager.this._context.clock().now()+DELAY);
private void syncKeys(File keyDir) { KeyManager.this._context.jobQueue().addJob(this);
syncPrivateKey(keyDir); }
syncPublicKey(keyDir);
syncSigningKey(keyDir); private void syncKeys(File keyDir) {
syncVerificationKey(keyDir); syncPrivateKey(keyDir);
} syncPublicKey(keyDir);
syncSigningKey(keyDir);
private void syncPrivateKey(File keyDir) { syncVerificationKey(keyDir);
File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_ENC); }
boolean exists = (_privateKey != null);
if (!exists) private void syncPrivateKey(File keyDir) {
_privateKey = new PrivateKey(); File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_ENC);
_privateKey = (PrivateKey)syncKey(keyFile, _privateKey, exists); boolean exists = (_privateKey != null);
} if (!exists)
private void syncPublicKey(File keyDir) { _privateKey = new PrivateKey();
File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_ENC); _privateKey = (PrivateKey)syncKey(keyFile, _privateKey, exists);
boolean exists = (_publicKey != null); }
if (!exists) private void syncPublicKey(File keyDir) {
_publicKey = new PublicKey(); File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_ENC);
_publicKey = (PublicKey)syncKey(keyFile, _publicKey, exists); boolean exists = (_publicKey != null);
} if (!exists)
_publicKey = new PublicKey();
private void syncSigningKey(File keyDir) { _publicKey = (PublicKey)syncKey(keyFile, _publicKey, exists);
File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_SIGNING); }
boolean exists = (_signingPrivateKey != null);
if (!exists) private void syncSigningKey(File keyDir) {
_signingPrivateKey = new SigningPrivateKey(); File keyFile = new File(keyDir, KeyManager.KEYFILE_PRIVATE_SIGNING);
_signingPrivateKey = (SigningPrivateKey)syncKey(keyFile, _signingPrivateKey, exists); boolean exists = (_signingPrivateKey != null);
} if (!exists)
private void syncVerificationKey(File keyDir) { _signingPrivateKey = new SigningPrivateKey();
File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_SIGNING); _signingPrivateKey = (SigningPrivateKey)syncKey(keyFile, _signingPrivateKey, exists);
boolean exists = (_signingPublicKey != null); }
if (!exists) private void syncVerificationKey(File keyDir) {
_signingPublicKey = new SigningPublicKey(); File keyFile = new File(keyDir, KeyManager.KEYFILE_PUBLIC_SIGNING);
_signingPublicKey = (SigningPublicKey)syncKey(keyFile, _signingPublicKey, exists); boolean exists = (_signingPublicKey != null);
} if (!exists)
_signingPublicKey = new SigningPublicKey();
private DataStructure syncKey(File keyFile, DataStructure structure, boolean exists) { _signingPublicKey = (SigningPublicKey)syncKey(keyFile, _signingPublicKey, exists);
FileOutputStream out = null; }
FileInputStream in = null;
try { private DataStructure syncKey(File keyFile, DataStructure structure, boolean exists) {
if (exists) { FileOutputStream out = null;
out = new FileOutputStream(keyFile); FileInputStream in = null;
structure.writeBytes(out); try {
return structure; if (exists) {
} else { out = new FileOutputStream(keyFile);
if (keyFile.exists()) { structure.writeBytes(out);
in = new FileInputStream(keyFile); return structure;
structure.readBytes(in); } else {
return structure; if (keyFile.exists()) {
} else { in = new FileInputStream(keyFile);
// we don't have it, and its not on disk. oh well. structure.readBytes(in);
return null; return structure;
} } else {
} // we don't have it, and its not on disk. oh well.
} catch (IOException ioe) { return null;
_log.error("Error syncing the structure to " + keyFile.getAbsolutePath(), ioe); }
} catch (DataFormatException dfe) { }
_log.error("Error syncing the structure with " + keyFile.getAbsolutePath(), dfe); } catch (IOException ioe) {
} finally { _log.error("Error syncing the structure to " + keyFile.getAbsolutePath(), ioe);
if (out != null) try { out.close(); } catch (IOException ioe) {} } catch (DataFormatException dfe) {
if (in != null) try { in.close(); } catch (IOException ioe) {} _log.error("Error syncing the structure with " + keyFile.getAbsolutePath(), dfe);
} } finally {
if (out != null) try { out.close(); } catch (IOException ioe) {}
if (exists) if (in != null) try { in.close(); } catch (IOException ioe) {}
return structure; }
else
return null; if (exists)
} return structure;
else
public String getName() { return "Synchronize Keys to Disk"; } return null;
}
public String getName() { return "Synchronize Keys to Disk"; }
} }
} }

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,19 +59,19 @@ 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 {
_doLog = DEFAULT_KEEP_MESSAGE_HISTORY; _doLog = DEFAULT_KEEP_MESSAGE_HISTORY;
} }
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;
if (_context.router().getRouterInfo() == null) {
_reinitializeJob.getTiming().setStartAfter(_context.clock().now()+5000);
_context.jobQueue().addJob(_reinitializeJob);
} else {
String filename = null;
filename = _context.router().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME);
if ( (filename == null) || (filename.trim().length() <= 0) )
filename = DEFAULT_MESSAGE_HISTORY_FILENAME;
_doLog = DEFAULT_KEEP_MESSAGE_HISTORY;
_historyFile = filename;
_localIdent = getName(_context.routerHash());
_unwrittenEntries = new LinkedList();
updateSettings();
addEntry(getPrefix() + "** Router initialized (started up or changed identities)");
_context.jobQueue().addJob(_writeJob);
_submitMessageHistoryJob.getTiming().setStartAfter(_context.clock().now() + 2*60*1000);
_context.jobQueue().addJob(_submitMessageHistoryJob);
}
} }
public static void initialize(boolean forceReinitialize) {
if ( (!forceReinitialize) && (_instance != null) ) return; private final class ReinitializeJob extends JobImpl {
private ReinitializeJob() {
if (Router.getInstance().getRouterInfo() == null) { super(MessageHistory.this._context);
ReinitializeJob j = ReinitializeJob.getInstance(); }
j.getTiming().setStartAfter(Clock.getInstance().now()+5000); public void runJob() {
JobQueue.getInstance().addJob(j); initialize(true);
} else { }
String filename = null; public String getName() { return "Reinitialize message history"; }
filename = Router.getInstance().getConfigSetting(PROP_MESSAGE_HISTORY_FILENAME);
if ( (filename == null) || (filename.trim().length() <= 0) )
filename = DEFAULT_MESSAGE_HISTORY_FILENAME;
MessageHistory hist = new MessageHistory(Router.getInstance().getRouterInfo().getIdentity().getHash(), filename);
setInstance(hist);
hist.updateSettings();
getInstance().addEntry(getInstance().getPrefix() + "** Router initialized (started up or changed identities)");
JobQueue.getInstance().addJob(new WriteJob());
SubmitMessageHistoryJob histJob = new SubmitMessageHistoryJob();
histJob.getTiming().setStartAfter(Clock.getInstance().now() + 2*60*1000);
JobQueue.getInstance().addJob(histJob);
}
}
private static final class ReinitializeJob extends JobImpl {
private final static ReinitializeJob _jobInstance = new ReinitializeJob();
public final static ReinitializeJob getInstance() { return _jobInstance; }
private ReinitializeJob() {
super();
}
public void runJob() {
MessageHistory.initialize();
}
public String getName() { return "Reinitialize message history"; }
}
/**
* Create a component to monitor the message history of the router.
*
* @param localIdent Hash of local identity
* @param filename file to log trace info to
*/
private MessageHistory(Hash localIdent, String filename) {
_doLog = DEFAULT_KEEP_MESSAGE_HISTORY;
_historyFile = filename;
_localIdent = getName(localIdent);
_unwrittenEntries = new LinkedList();
} }
/** /**
@ -151,20 +128,20 @@ public class MessageHistory {
* @param replyThrough the gateway of the tunnel that the sourceRoutePeer will be sending to * @param replyThrough the gateway of the tunnel that the sourceRoutePeer will be sending to
*/ */
public void requestTunnelCreate(TunnelId createTunnel, TunnelId outTunnel, Hash peerRequested, Hash nextPeer, Hash sourceRoutePeer, TunnelId replyTunnel, Hash replyThrough) { public void requestTunnelCreate(TunnelId createTunnel, TunnelId outTunnel, Hash peerRequested, Hash nextPeer, Hash sourceRoutePeer, TunnelId replyTunnel, Hash replyThrough) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("request [").append(getName(peerRequested)).append("] to create tunnel ["); buf.append("request [").append(getName(peerRequested)).append("] to create tunnel [");
buf.append(createTunnel.getTunnelId()).append("] "); buf.append(createTunnel.getTunnelId()).append("] ");
if (nextPeer != null) if (nextPeer != null)
buf.append("(next [").append(getName(nextPeer)).append("]) "); buf.append("(next [").append(getName(nextPeer)).append("]) ");
if (outTunnel != null) if (outTunnel != null)
buf.append("via [").append(outTunnel.getTunnelId()).append("] "); buf.append("via [").append(outTunnel.getTunnelId()).append("] ");
if (sourceRoutePeer != null) if (sourceRoutePeer != null)
buf.append("with replies routed through [").append(getName(sourceRoutePeer)).append("] "); buf.append("with replies routed through [").append(getName(sourceRoutePeer)).append("] ");
if ( (replyTunnel != null) && (replyThrough != null) ) if ( (replyTunnel != null) && (replyThrough != null) )
buf.append("who forwards it through [").append(replyTunnel.getTunnelId()).append("] on [").append(getName(replyThrough)).append("]"); buf.append("who forwards it through [").append(replyTunnel.getTunnelId()).append("] on [").append(getName(replyThrough)).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -178,14 +155,14 @@ public class MessageHistory {
* @param sourceRoutePeer peer through whom we should send our garlic routed ok through * @param sourceRoutePeer peer through whom we should send our garlic routed ok through
*/ */
public void receiveTunnelCreate(TunnelId createTunnel, Hash nextPeer, Date expire, boolean ok, Hash sourceRoutePeer) { public void receiveTunnelCreate(TunnelId createTunnel, Hash nextPeer, Date expire, boolean ok, Hash sourceRoutePeer) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("receive tunnel create [").append(createTunnel.getTunnelId()).append("] "); buf.append("receive tunnel create [").append(createTunnel.getTunnelId()).append("] ");
if (nextPeer != null) if (nextPeer != null)
buf.append("(next [").append(getName(nextPeer)).append("]) "); buf.append("(next [").append(getName(nextPeer)).append("]) ");
buf.append("ok? ").append(ok).append(" expiring on [").append(getTime(expire)).append("]"); buf.append("ok? ").append(ok).append(" expiring on [").append(getTime(expire)).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -195,22 +172,22 @@ public class MessageHistory {
* @param tunnel tunnel joined * @param tunnel tunnel joined
*/ */
public void tunnelJoined(String state, TunnelInfo tunnel) { public void tunnelJoined(String state, TunnelInfo tunnel) {
if (!_doLog) return; if (!_doLog) return;
if (tunnel == null) return; if (tunnel == null) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("joining tunnel [").append(tunnel.getTunnelId().getTunnelId()).append("] as [").append(state).append("] "); buf.append("joining tunnel [").append(tunnel.getTunnelId().getTunnelId()).append("] as [").append(state).append("] ");
buf.append(" (next: "); buf.append(" (next: ");
TunnelInfo cur = tunnel; TunnelInfo cur = tunnel;
while (cur.getNextHopInfo() != null) { while (cur.getNextHopInfo() != null) {
buf.append('[').append(getName(cur.getNextHopInfo().getThisHop())); buf.append('[').append(getName(cur.getNextHopInfo().getThisHop()));
buf.append("], "); buf.append("], ");
cur = cur.getNextHopInfo(); cur = cur.getNextHopInfo();
} }
if (cur.getNextHop() != null) if (cur.getNextHop() != null)
buf.append('[').append(getName(cur.getNextHop())).append(']'); buf.append('[').append(getName(cur.getNextHop())).append(']');
buf.append(") expiring on [").append(getTime(new Date(tunnel.getSettings().getExpiration()))).append("]"); buf.append(") expiring on [").append(getTime(new Date(tunnel.getSettings().getExpiration()))).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -219,12 +196,12 @@ public class MessageHistory {
* @param tunnel tunnel failed * @param tunnel tunnel failed
*/ */
public void tunnelFailed(TunnelId tunnel) { public void tunnelFailed(TunnelId tunnel) {
if (!_doLog) return; if (!_doLog) return;
if (tunnel == null) return; if (tunnel == null) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("failing tunnel [").append(tunnel.getTunnelId()).append("]"); buf.append("failing tunnel [").append(tunnel.getTunnelId()).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -235,24 +212,24 @@ public class MessageHistory {
* @param timeToTest milliseconds to verify the tunnel * @param timeToTest milliseconds to verify the tunnel
*/ */
public void tunnelValid(TunnelInfo tunnel, long timeToTest) { public void tunnelValid(TunnelInfo tunnel, long timeToTest) {
if (!_doLog) return; if (!_doLog) return;
if (tunnel == null) return; if (tunnel == null) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("tunnel ").append(tunnel.getTunnelId().getTunnelId()).append(" tested ok after ").append(timeToTest).append("ms (containing "); buf.append("tunnel ").append(tunnel.getTunnelId().getTunnelId()).append(" tested ok after ").append(timeToTest).append("ms (containing ");
TunnelInfo cur = tunnel; TunnelInfo cur = tunnel;
while (cur != null) { while (cur != null) {
buf.append('[').append(getName(cur.getThisHop())).append("], "); buf.append('[').append(getName(cur.getThisHop())).append("], ");
if (cur.getNextHopInfo() != null) { if (cur.getNextHopInfo() != null) {
cur = cur.getNextHopInfo(); cur = cur.getNextHopInfo();
} else { } else {
if (cur.getNextHop() != null) if (cur.getNextHop() != null)
buf.append('[').append(getName(cur.getNextHop())).append(']'); buf.append('[').append(getName(cur.getNextHop())).append(']');
cur = null; cur = null;
} }
} }
buf.append(')'); buf.append(')');
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -260,15 +237,15 @@ public class MessageHistory {
* *
*/ */
public void tunnelRejected(Hash peer, TunnelId tunnel, Hash replyThrough, String reason) { public void tunnelRejected(Hash peer, TunnelId tunnel, Hash replyThrough, String reason) {
if (!_doLog) return; if (!_doLog) return;
if ( (tunnel == null) || (peer == null) ) return; if ( (tunnel == null) || (peer == null) ) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("tunnel [").append(tunnel.getTunnelId()).append("] was rejected by ["); buf.append("tunnel [").append(tunnel.getTunnelId()).append("] was rejected by [");
buf.append(getName(peer)).append("] for [").append(reason).append("]"); buf.append(getName(peer)).append("] for [").append(reason).append("]");
if (replyThrough != null) if (replyThrough != null)
buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]"); buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -277,15 +254,15 @@ public class MessageHistory {
* *
*/ */
public void tunnelRequestTimedOut(Hash peer, TunnelId tunnel, Hash replyThrough) { public void tunnelRequestTimedOut(Hash peer, TunnelId tunnel, Hash replyThrough) {
if (!_doLog) return; if (!_doLog) return;
if ( (tunnel == null) || (peer == null) ) return; if ( (tunnel == null) || (peer == null) ) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("tunnel [").append(tunnel.getTunnelId()).append("] timed out on ["); buf.append("tunnel [").append(tunnel.getTunnelId()).append("] timed out on [");
buf.append(getName(peer)).append("]"); buf.append(getName(peer)).append("]");
if (replyThrough != null) if (replyThrough != null)
buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]"); buf.append(" with their reply intended to come through [").append(getName(replyThrough)).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -296,24 +273,24 @@ public class MessageHistory {
* @param from peer that sent us this message (if known) * @param from peer that sent us this message (if known)
*/ */
public void droppedTunnelMessage(TunnelId id, Hash from) { public void droppedTunnelMessage(TunnelId id, Hash from) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("dropped message for unknown tunnel [").append(id.getTunnelId()).append("] from [").append(getName(from)).append("]"); buf.append("dropped message for unknown tunnel [").append(id.getTunnelId()).append("] from [").append(getName(from)).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
* We received another message we weren't waiting for and don't know how to handle * We received another message we weren't waiting for and don't know how to handle
*/ */
public void droppedOtherMessage(I2NPMessage message) { public void droppedOtherMessage(I2NPMessage message) {
if (!_doLog) return; if (!_doLog) return;
if (message == null) return; if (message == null) return;
StringBuffer buf = new StringBuffer(512); StringBuffer buf = new StringBuffer(512);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("dropped [").append(message.getClass().getName()).append("] ").append(message.getUniqueId()); buf.append("dropped [").append(message.getClass().getName()).append("] ").append(message.getUniqueId());
buf.append(" [").append(message.toString()).append("]"); buf.append(" [").append(message.toString()).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -322,16 +299,16 @@ public class MessageHistory {
* @param sentMessage message sent that didn't receive a reply * @param sentMessage message sent that didn't receive a reply
*/ */
public void replyTimedOut(OutNetMessage sentMessage) { public void replyTimedOut(OutNetMessage sentMessage) {
if (!_doLog) return; if (!_doLog) return;
if (sentMessage == null) return; if (sentMessage == null) return;
StringBuffer buf = new StringBuffer(512); StringBuffer buf = new StringBuffer(512);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("timed out waiting for a reply to [").append(sentMessage.getMessage().getClass().getName()); buf.append("timed out waiting for a reply to [").append(sentMessage.getMessage().getClass().getName());
buf.append("] [").append(sentMessage.getMessage().getUniqueId()).append("] expiring on ["); buf.append("] [").append(sentMessage.getMessage().getUniqueId()).append("] expiring on [");
if (sentMessage != null) if (sentMessage != null)
buf.append(getTime(new Date(sentMessage.getReplySelector().getExpiration()))); buf.append(getTime(new Date(sentMessage.getReplySelector().getExpiration())));
buf.append("] ").append(sentMessage.getReplySelector().toString()); buf.append("] ").append(sentMessage.getReplySelector().toString());
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -342,11 +319,11 @@ public class MessageHistory {
* @param error error message related to the processing of the message * @param error error message related to the processing of the message
*/ */
public void messageProcessingError(long messageId, String messageType, String error) { public void messageProcessingError(long messageId, String messageType, String error) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("Error processing [").append(messageType).append("] [").append(messageId).append("] failed with [").append(error).append("]"); buf.append("Error processing [").append(messageType).append("] [").append(messageId).append("] failed with [").append(error).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -360,17 +337,17 @@ public class MessageHistory {
* @param sentOk whether the message was sent successfully * @param sentOk whether the message was sent successfully
*/ */
public void sendMessage(String messageType, long messageId, Date expiration, Hash peer, boolean sentOk) { public void sendMessage(String messageType, long messageId, Date expiration, Hash peer, boolean sentOk) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("send [").append(messageType).append("] message [").append(messageId).append("] "); buf.append("send [").append(messageType).append("] message [").append(messageId).append("] ");
buf.append("to [").append(getName(peer)).append("] "); buf.append("to [").append(getName(peer)).append("] ");
buf.append("expiring on [").append(getTime(expiration)).append("] "); buf.append("expiring on [").append(getTime(expiration)).append("] ");
if (sentOk) if (sentOk)
buf.append("successfully"); buf.append("successfully");
else else
buf.append("failed"); buf.append("failed");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -385,20 +362,20 @@ public class MessageHistory {
* *
*/ */
public void receiveMessage(String messageType, long messageId, Date expiration, Hash from, boolean isValid) { public void receiveMessage(String messageType, long messageId, Date expiration, Hash from, boolean isValid) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("receive [").append(messageType).append("] with id [").append(messageId).append("] "); buf.append("receive [").append(messageType).append("] with id [").append(messageId).append("] ");
if (from != null) if (from != null)
buf.append("from [").append(getName(from)).append("] "); buf.append("from [").append(getName(from)).append("] ");
buf.append("expiring on [").append(getTime(expiration)).append("] valid? ").append(isValid); buf.append("expiring on [").append(getTime(expiration)).append("] valid? ").append(isValid);
addEntry(buf.toString()); addEntry(buf.toString());
if (messageType.equals("net.i2p.data.i2np.TunnelMessage")) { if (messageType.equals("net.i2p.data.i2np.TunnelMessage")) {
//_log.warn("ReceiveMessage tunnel message ["+messageId+"]", new Exception("Receive tunnel")); //_log.warn("ReceiveMessage tunnel message ["+messageId+"]", new Exception("Receive tunnel"));
} }
} }
public void receiveMessage(String messageType, long messageId, Date expiration, boolean isValid) { public void receiveMessage(String messageType, long messageId, Date expiration, boolean isValid) {
receiveMessage(messageType, messageId, expiration, null, isValid); receiveMessage(messageType, messageId, expiration, null, isValid);
} }
/** /**
@ -410,12 +387,12 @@ public class MessageHistory {
* @param containerMessageId the unique message id of the message * @param containerMessageId the unique message id of the message
*/ */
public void wrap(String bodyMessageType, long bodyMessageId, String containerMessageType, long containerMessageId) { public void wrap(String bodyMessageType, long bodyMessageId, String containerMessageType, long containerMessageId) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("Wrap message [").append(bodyMessageType).append("] id [").append(bodyMessageId).append("] "); buf.append("Wrap message [").append(bodyMessageType).append("] id [").append(bodyMessageId).append("] ");
buf.append("in [").append(containerMessageType).append("] id [").append(containerMessageId).append("]"); buf.append("in [").append(containerMessageType).append("] id [").append(containerMessageId).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -423,11 +400,11 @@ public class MessageHistory {
* *
*/ */
public void receivePayloadMessage(long messageId) { public void receivePayloadMessage(long messageId) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(64); StringBuffer buf = new StringBuffer(64);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("Receive payload message [").append(messageId).append("]"); buf.append("Receive payload message [").append(messageId).append("]");
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -438,11 +415,11 @@ public class MessageHistory {
* @param timeToSend how long it took to send the message * @param timeToSend how long it took to send the message
*/ */
public void sendPayloadMessage(long messageId, boolean successfullySent, long timeToSend) { public void sendPayloadMessage(long messageId, boolean successfullySent, long timeToSend) {
if (!_doLog) return; if (!_doLog) return;
StringBuffer buf = new StringBuffer(128); StringBuffer buf = new StringBuffer(128);
buf.append(getPrefix()); buf.append(getPrefix());
buf.append("Send payload message in [").append(messageId).append("] in [").append(timeToSend).append("] successfully? ").append(successfullySent); buf.append("Send payload message in [").append(messageId).append("] in [").append(timeToSend).append("] successfully? ").append(successfullySent);
addEntry(buf.toString()); addEntry(buf.toString());
} }
/** /**
@ -450,27 +427,27 @@ public class MessageHistory {
* *
*/ */
private final static String getName(Hash router) { private final static String getName(Hash router) {
if (router == null) return "unknown"; if (router == null) return "unknown";
String str = router.toBase64(); String str = router.toBase64();
if ( (str == null) || (str.length() < 6) ) return "invalid"; if ( (str == null) || (str.length() < 6) ) return "invalid";
return str.substring(0, 6); return str.substring(0, 6);
} }
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();
} }
private final static SimpleDateFormat _fmt = new SimpleDateFormat("yy/MM/dd.HH:mm:ss.SSS"); private final static SimpleDateFormat _fmt = new SimpleDateFormat("yy/MM/dd.HH:mm:ss.SSS");
static { static {
_fmt.setTimeZone(TimeZone.getTimeZone("GMT")); _fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
} }
private final static String getTime(Date when) { private final static String getTime(Date when) {
synchronized (_fmt) { synchronized (_fmt) {
return _fmt.format(when); return _fmt.format(when);
} }
} }
/** /**
@ -479,27 +456,27 @@ public class MessageHistory {
* *
*/ */
private void addEntry(String entry) { private void addEntry(String entry) {
if (entry == null) return; if (entry == null) return;
int sz = 0; int sz = 0;
synchronized (_unwrittenEntries) { synchronized (_unwrittenEntries) {
_unwrittenEntries.add(entry); _unwrittenEntries.add(entry);
sz = _unwrittenEntries.size(); sz = _unwrittenEntries.size();
} }
if (sz > FLUSH_SIZE) if (sz > FLUSH_SIZE)
flushEntries(); flushEntries();
} }
/** /**
* Write out any unwritten entries, and clear the pending list * Write out any unwritten entries, and clear the pending list
*/ */
private void flushEntries() { private void flushEntries() {
if (_doPause) return; if (_doPause) return;
List entries = null; List entries = null;
synchronized (_unwrittenEntries) { synchronized (_unwrittenEntries) {
entries = new LinkedList(_unwrittenEntries); entries = new LinkedList(_unwrittenEntries);
_unwrittenEntries.clear(); _unwrittenEntries.clear();
} }
writeEntries(entries); writeEntries(entries);
} }
/** /**
@ -507,41 +484,46 @@ public class MessageHistory {
* *
*/ */
private void writeEntries(List entries) { private void writeEntries(List entries) {
if (!_doLog) return; if (!_doLog) return;
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
fos = new FileOutputStream(_historyFile, true); fos = new FileOutputStream(_historyFile, true);
for (Iterator iter = entries.iterator(); iter.hasNext(); ) { for (Iterator iter = entries.iterator(); iter.hasNext(); ) {
String entry = (String)iter.next(); String entry = (String)iter.next();
fos.write(entry.getBytes()); fos.write(entry.getBytes());
fos.write(NL); fos.write(NL);
} }
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error writing trace entries", ioe); _log.error("Error writing trace entries", ioe);
} finally { } finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {} if (fos != null) try { fos.close(); } catch (IOException ioe) {}
} }
} }
/** 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 String getName() { return "Write History Entries"; } public WriteJob() {
public void runJob() { super(MessageHistory.this._context);
MessageHistory.getInstance().flushEntries(); }
MessageHistory.getInstance().updateSettings(); public String getName() { return "Write History Entries"; }
requeue(WRITE_DELAY); public void runJob() {
} flushEntries();
updateSettings();
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);
hist.addEntry("you smell before"); //, new Hash(new byte[32]), "messageHistory.txt");
hist.getInstance().setDoLog(true); hist.setDoLog(false);
hist.addEntry("you smell after"); hist.addEntry("you smell before");
hist.getInstance().setDoLog(false); hist.setDoLog(true);
hist.addEntry("you smell finished"); hist.addEntry("you smell after");
hist.flushEntries(); hist.setDoLog(false);
hist.addEntry("you smell finished");
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,88 +47,87 @@ 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");
return false; return false;
} }
boolean isDuplicate = noteReception(messageId, expiration); boolean isDuplicate = noteReception(messageId, expiration);
if (isDuplicate) { if (isDuplicate) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
_log.warn("Rejecting message " + messageId + " because it is a duplicate", new Exception("Duplicate origin")); _log.warn("Rejecting message " + messageId + " because it is a duplicate", new Exception("Duplicate origin"));
return false; return false;
} else { } else {
if (_log.shouldLog(Log.DEBUG)) if (_log.shouldLog(Log.DEBUG))
_log.debug("Accepting message " + messageId + " because it is NOT a duplicate", new Exception("Original origin")); _log.debug("Accepting message " + messageId + " because it is NOT a duplicate", new Exception("Original origin"));
return true; return true;
} }
} }
/** /**
* Note that we've received the message (which has the expiration given). * Note that we've received the message (which has the expiration given).
* This functionality will need to be reworked for I2P 3.0 when we take into * This functionality will need to be reworked for I2P 3.0 when we take into
* consideration messages with significant user specified delays (since we dont * consideration messages with significant user specified delays (since we dont
* want to keep an infinite number of messages in RAM, etc) * want to keep an infinite number of messages in RAM, etc)
* *
* @return true if we HAVE already seen this message, false if not * @return true if we HAVE already seen this message, false if not
*/ */
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 {
long date = messageExpiration; long date = messageExpiration;
while (_receivedIdExpirations.containsKey(new Long(date))) while (_receivedIdExpirations.containsKey(new Long(date)))
date++; date++;
_receivedIdExpirations.put(new Long(date), id); _receivedIdExpirations.put(new Long(date), id);
_receivedIds.add(id); _receivedIds.add(id);
return false; return false;
} }
} }
} }
/** /**
* Clean the ids that we no longer need to keep track of to prevent replay * Clean the ids that we no longer need to keep track of to prevent replay
* attacks. * attacks.
* *
*/ */
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);
} }
} }
/** /**
* Clean the ids that we no longer need to keep track of to prevent replay * Clean the ids that we no longer need to keep track of to prevent replay
* attacks - only call this from within a block synchronized on the received ID lock. * attacks - only call this from within a block synchronized on the received ID lock.
* *
*/ */
private void locked_cleanReceivedIds(long now) { private void locked_cleanReceivedIds(long now) {
Set toRemoveIds = new HashSet(4); Set toRemoveIds = new HashSet(4);
Set toRemoveDates = new HashSet(4); Set toRemoveDates = new HashSet(4);
for (Iterator iter = _receivedIdExpirations.keySet().iterator(); iter.hasNext(); ) { for (Iterator iter = _receivedIdExpirations.keySet().iterator(); iter.hasNext(); ) {
Long date = (Long)iter.next(); Long date = (Long)iter.next();
if (date.longValue() <= now) { if (date.longValue() <= now) {
// no need to keep track of things in the past // no need to keep track of things in the past
toRemoveDates.add(date); toRemoveDates.add(date);
toRemoveIds.add(_receivedIdExpirations.get(date)); toRemoveIds.add(_receivedIdExpirations.get(date));
} else { } else {
// the expiration is in the future, we still need to keep track of // the expiration is in the future, we still need to keep track of
// it to prevent replays // it to prevent replays
break; break;
} }
} }
for (Iterator iter = toRemoveDates.iterator(); iter.hasNext(); ) for (Iterator iter = toRemoveDates.iterator(); iter.hasNext(); )
_receivedIdExpirations.remove(iter.next()); _receivedIdExpirations.remove(iter.next());
for (Iterator iter = toRemoveIds.iterator(); iter.hasNext(); ) for (Iterator iter = toRemoveIds.iterator(); iter.hasNext(); )
_receivedIds.remove(iter.next()); _receivedIds.remove(iter.next());
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,33 +51,35 @@ 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);
} }
public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {} public void lookupLeaseSet(Hash key, Job onFindJob, Job onFailedLookupJob, long timeoutMs) {}
public LeaseSet lookupLeaseSetLocally(Hash key) { return null; } public LeaseSet lookupLeaseSetLocally(Hash key) { return null; }
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) {}
public void publish(RouterInfo localRouterInfo) {} public void publish(RouterInfo localRouterInfo) {}
public LeaseSet store(Hash key, LeaseSet leaseSet) { return leaseSet; } public LeaseSet store(Hash key, LeaseSet leaseSet) { return leaseSet; }
public RouterInfo store(Hash key, RouterInfo routerInfo) { public RouterInfo store(Hash key, RouterInfo routerInfo) {
_routers.put(key, routerInfo); _routers.put(key, routerInfo);
return routerInfo; return routerInfo;
} }
public void unpublish(LeaseSet localLeaseSet) {} public void unpublish(LeaseSet localLeaseSet) {}
public void fail(Hash dbEntry) {} public void fail(Hash dbEntry) {}

View File

@ -1,9 +1,9 @@
package net.i2p.router; package net.i2p.router;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -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;
@ -49,53 +50,55 @@ public class OutNetMessage {
private long _created; private long _created;
/** for debugging, contains a mapping of even name to Long (e.g. "begin sending", "handleOutbound", etc) */ /** for debugging, contains a mapping of even name to Long (e.g. "begin sending", "handleOutbound", etc) */
private HashMap _timestamps; private HashMap _timestamps;
/** /**
* contains a list of timestamp event names in the order they were fired * contains a list of timestamp event names in the order they were fired
* (some JVMs have less than 10ms resolution, so the Long above doesn't guarantee order) * (some JVMs have less than 10ms resolution, so the Long above doesn't guarantee order)
*/ */
private List _timestampOrder; private List _timestampOrder;
public OutNetMessage() { public OutNetMessage(RouterContext context) {
setTarget(null); _context = context;
_message = null; _log = context.logManager().getLog(OutNetMessage.class);
_messageSize = 0; setTarget(null);
setPriority(-1); _message = null;
setExpiration(-1); _messageSize = 0;
setOnSendJob(null); setPriority(-1);
setOnFailedSendJob(null); setExpiration(-1);
setOnReplyJob(null); setOnSendJob(null);
setOnFailedReplyJob(null); setOnFailedSendJob(null);
setReplySelector(null); setOnReplyJob(null);
_timestamps = new HashMap(8); setOnFailedReplyJob(null);
_timestampOrder = new LinkedList(); setReplySelector(null);
_failedTransports = new HashSet(); _timestamps = new HashMap(8);
_sendBegin = 0; _timestampOrder = new LinkedList();
_createdBy = new Exception("Created by"); _failedTransports = new HashSet();
_created = Clock.getInstance().now(); _sendBegin = 0;
timestamp("Created"); _createdBy = new Exception("Created by");
_created = context.clock().now();
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);
} }
} }
public Map getTimestamps() { public Map getTimestamps() {
synchronized (_timestamps) { synchronized (_timestamps) {
return (Map)_timestamps.clone(); return (Map)_timestamps.clone();
} }
} }
public Long getTimestamp(String eventName) { public Long getTimestamp(String eventName) {
synchronized (_timestamps) { synchronized (_timestamps) {
return (Long)_timestamps.get(eventName); return (Long)_timestamps.get(eventName);
} }
} }
public Exception getCreatedBy() { return _createdBy; } public Exception getCreatedBy() { return _createdBy; }
/** /**
* Specifies the router to which the message should be delivered. * Specifies the router to which the message should be delivered.
* *
*/ */
public RouterInfo getTarget() { return _target; } public RouterInfo getTarget() { return _target; }
@ -105,48 +108,48 @@ public class OutNetMessage {
* *
*/ */
public I2NPMessage getMessage() { return _message; } public I2NPMessage getMessage() { return _message; }
public void setMessage(I2NPMessage msg) { public void setMessage(I2NPMessage msg) {
_message = msg; _message = msg;
} }
public long getMessageSize() { public long getMessageSize() {
if (_messageSize <= 0) { if (_messageSize <= 0) {
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages
_message.writeBytes(baos); _message.writeBytes(baos);
long sz = baos.size(); long sz = baos.size();
baos.reset(); baos.reset();
_messageSize = sz; _messageSize = sz;
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe); _log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe); _log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe);
} }
} }
return _messageSize; return _messageSize;
} }
public byte[] getMessageData() { public byte[] getMessageData() {
if (_message == null) { if (_message == null) {
return null; return null;
} else { } else {
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); // large enough to hold most messages
_message.writeBytes(baos); _message.writeBytes(baos);
byte data[] = baos.toByteArray(); byte data[] = baos.toByteArray();
baos.reset(); baos.reset();
return data; return data;
} catch (DataFormatException dfe) { } catch (DataFormatException dfe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe); _log.error("Error serializing the I2NPMessage for the OutNetMessage", dfe);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe); _log.error("Error serializing the I2NPMessage for the OutNetMessage", ioe);
} }
return null; return null;
} }
} }
/** /**
* Specify the priority of the message, where higher numbers are higher * Specify the priority of the message, where higher numbers are higher
* priority. Higher priority messages should be delivered before lower * priority. Higher priority messages should be delivered before lower
* priority ones, though some algorithm may be used to avoid starvation. * priority ones, though some algorithm may be used to avoid starvation.
* *
*/ */
@ -154,15 +157,15 @@ public class OutNetMessage {
public void setPriority(int priority) { _priority = priority; } public void setPriority(int priority) { _priority = priority; }
/** /**
* Specify the # ms since the epoch after which if the message has not been * Specify the # ms since the epoch after which if the message has not been
* sent the OnFailedSend job should be fired and the message should be * sent the OnFailedSend job should be fired and the message should be
* removed from the pool. If the message has already been sent, this * removed from the pool. If the message has already been sent, this
* expiration is ignored and the expiration from the ReplySelector is used. * expiration is ignored and the expiration from the ReplySelector is used.
* *
*/ */
public long getExpiration() { return _expiration; } public long getExpiration() { return _expiration; }
public void setExpiration(long expiration) { _expiration = expiration; } public void setExpiration(long expiration) { _expiration = expiration; }
/** /**
* After the message is successfully passed to the router specified, the * After the message is successfully passed to the router specified, the
* given job is enqueued. * given job is enqueued.
* *
*/ */
@ -199,74 +202,74 @@ 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);
buf.append("[OutNetMessage contains "); buf.append("[OutNetMessage contains ");
if (_message == null) { if (_message == null) {
buf.append("*no message*"); buf.append("*no message*");
} else { } else {
buf.append("a ").append(_messageSize).append(" byte "); buf.append("a ").append(_messageSize).append(" byte ");
buf.append(_message.getClass().getName()); buf.append(_message.getClass().getName());
} }
buf.append(" expiring on ").append(new Date(_expiration)); buf.append(" expiring on ").append(new Date(_expiration));
buf.append(" failed delivery on transports ").append(_failedTransports); buf.append(" failed delivery on transports ").append(_failedTransports);
if (_target == null) if (_target == null)
buf.append(" targetting no one in particular..."); buf.append(" targetting no one in particular...");
else else
buf.append(" targetting ").append(_target.getIdentity().getHash().toBase64()); buf.append(" targetting ").append(_target.getIdentity().getHash().toBase64());
if (_onReply != null) if (_onReply != null)
buf.append(" with onReply job: ").append(_onReply); buf.append(" with onReply job: ").append(_onReply);
if (_onSend != null) if (_onSend != null)
buf.append(" with onSend job: ").append(_onSend); buf.append(" with onSend job: ").append(_onSend);
if (_onFailedReply != null) if (_onFailedReply != null)
buf.append(" with onFailedReply job: ").append(_onFailedReply); buf.append(" with onFailedReply job: ").append(_onFailedReply);
if (_onFailedSend != null) if (_onFailedSend != null)
buf.append(" with onFailedSend job: ").append(_onFailedSend); buf.append(" with onFailedSend job: ").append(_onFailedSend);
buf.append(" {timestamps: \n"); buf.append(" {timestamps: \n");
synchronized (_timestamps) { synchronized (_timestamps) {
long lastWhen = -1; long lastWhen = -1;
for (int i = 0; i < _timestampOrder.size(); i++) { for (int i = 0; i < _timestampOrder.size(); i++) {
String name = (String)_timestampOrder.get(i); String name = (String)_timestampOrder.get(i);
Long when = (Long)_timestamps.get(name); Long when = (Long)_timestamps.get(name);
buf.append("\t["); buf.append("\t[");
long diff = when.longValue() - lastWhen; long diff = when.longValue() - lastWhen;
if ( (lastWhen > 0) && (diff > 500) ) if ( (lastWhen > 0) && (diff > 500) )
buf.append("**"); buf.append("**");
if (lastWhen > 0) if (lastWhen > 0)
buf.append(diff); buf.append(diff);
else else
buf.append(0); buf.append(0);
buf.append("ms: \t").append(name).append('=').append(formatDate(when.longValue())).append("]\n"); buf.append("ms: \t").append(name).append('=').append(formatDate(when.longValue())).append("]\n");
lastWhen = when.longValue(); lastWhen = when.longValue();
} }
} }
buf.append("}"); buf.append("}");
buf.append("]"); buf.append("]");
return buf.toString(); return buf.toString();
} }
private final static SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss.SSS"); private final static SimpleDateFormat _fmt = new SimpleDateFormat("HH:mm:ss.SSS");
private final static String formatDate(long when) { private final static String formatDate(long when) {
Date d = new Date(when); Date d = new Date(when);
synchronized (_fmt) { synchronized (_fmt) {
return _fmt.format(d); return _fmt.format(d);
} }
} }
public int hashCode() { public int hashCode() {
int rv = 0; int rv = 0;
rv += DataHelper.hashCode(_message); rv += DataHelper.hashCode(_message);
rv += DataHelper.hashCode(_target); rv += DataHelper.hashCode(_target);
// the others are pretty much inconsequential // the others are pretty much inconsequential
return rv; return rv;
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
return obj == this; // two OutNetMessages are different even if they contain the same message return obj == this; // two OutNetMessages are different even if they contain the same message
} }
} }

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,19 +39,7 @@ public class OutNetMessagePool {
* *
*/ */
public OutNetMessage getNext() { public OutNetMessage getNext() {
synchronized (_messageLists) { return null;
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;
}
} }
/** /**
@ -60,45 +47,35 @@ 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) { _context.messageRegistry().registerPending(msg);
OutboundMessageRegistry.getInstance().registerPending(msg); }
} _context.commSystem().processMessage(msg);
CommSystemFacade.getInstance().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) {
_log.error("Null message in the OutNetMessage: " + msg, new Exception("Someone fucked up")); _log.error("Null message in the OutNetMessage: " + msg, new Exception("Someone fucked up"));
return false; return false;
} }
if (msg.getTarget() == null) { if (msg.getTarget() == null) {
_log.error("No target in the OutNetMessage: " + msg, new Exception("Definitely a fuckup")); _log.error("No target in the OutNetMessage: " + msg, new Exception("Definitely a fuckup"));
return false; return false;
} }
if (msg.getPriority() < 0) { if (msg.getPriority() < 0) {
_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;
} }
return true; return true;
} }
/** /**
@ -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,45 +98,17 @@ 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) {
if ( (lhs == null) || (rhs == null) ) return 0; // invalid, but never used if ( (lhs == null) || (rhs == null) ) return 0; // invalid, but never used
if ( !(lhs instanceof Integer) || !(rhs instanceof Integer)) return 0; if ( !(lhs instanceof Integer) || !(rhs instanceof Integer)) return 0;
Integer lv = (Integer)lhs; Integer lv = (Integer)lhs;
Integer rv = (Integer)rhs; Integer rv = (Integer)rhs;
return - (lv.compareTo(rv)); return - (lv.compareTo(rv));
} }
} }
} }

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 { public interface 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);
/** /**
* 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,77 +15,83 @@ 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);
if (f.exists()) { if (f.exists()) {
FileInputStream fin = null; FileInputStream fin = null;
try { try {
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))
} catch (Throwable t) { _log.debug("Session keys loaded [not error] with " + expired
_log.error("Error reading in session key data", t); + " sets immediately expired");
} finally { } catch (Throwable t) {
if (fin != null) try { fin.close(); } catch (IOException ioe) {} _log.error("Error reading in session key data", t);
} } finally {
} 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;
} }
PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)o; PersistentSessionKeyManager mgr = (PersistentSessionKeyManager)o;
// only need for synchronization is during shutdown() // only need for synchronization is during shutdown()
synchronized (mgr) { synchronized (mgr) {
FileOutputStream fos = null; FileOutputStream fos = null;
try { try {
int expired = mgr.aggressiveExpire(); int expired = mgr.aggressiveExpire();
if (expired > 0) { if (expired > 0) {
_log.info("Agressive expired " + expired + " tag sets"); _log.info("Agressive expired " + expired + " tag sets");
} }
fos = new FileOutputStream(SESSION_KEY_FILE); fos = new FileOutputStream(SESSION_KEY_FILE);
mgr.saveState(fos); mgr.saveState(fos);
fos.flush(); fos.flush();
_log.debug("Session keys written"); _log.debug("Session keys written");
} catch (Throwable t) { } catch (Throwable t) {
_log.debug("Error writing session key state", t); _log.debug("Error writing session key state", t);
} finally { } finally {
if (fos != null) try { fos.close(); } catch (IOException ioe) {} if (fos != null) try { fos.close(); } catch (IOException ioe) {}
} }
} }
} }
public String renderStatusHTML() { return ""; } public String renderStatusHTML() { return ""; }
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"; }
public void runJob() { public void runJob() {
writeState(); writeState();
requeue(PERSIST_DELAY); requeue(PERSIST_DELAY);
} }
} }
} }

View File

@ -1,9 +1,9 @@
package net.i2p.router; package net.i2p.router;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -24,76 +24,82 @@ 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) {
_shitlist = new HashMap(100); _context = context;
_log = context.logManager().getLog(Shitlist.class);
_shitlist = new HashMap(100);
} }
public boolean shitlistRouter(Hash peer) { public boolean shitlistRouter(Hash peer) {
if (peer == null) return false; if (peer == null) return false;
boolean wasAlready = false; if (_context.routerHash().equals(peer)) {
if (_log.shouldLog(Log.INFO)) _log.error("wtf, why did we try to shitlist ourselves?", new Exception("shitfaced"));
_log.info("Shitlisting router " + peer.toBase64(), new Exception("Shitlist cause")); return false;
}
synchronized (_shitlist) { boolean wasAlready = false;
Date oldDate = (Date)_shitlist.put(peer, new Date(Clock.getInstance().now())); if (_log.shouldLog(Log.INFO))
wasAlready = (null == oldDate); _log.info("Shitlisting router " + peer.toBase64(), new Exception("Shitlist cause"));
}
NetworkDatabaseFacade.getInstance().fail(peer); synchronized (_shitlist) {
TunnelManagerFacade.getInstance().peerFailed(peer); Date oldDate = (Date)_shitlist.put(peer, new Date(_context.clock().now()));
return wasAlready; wasAlready = (null == oldDate);
}
_context.netDb().fail(peer);
_context.tunnelManager().peerFailed(peer);
return wasAlready;
} }
public void unshitlistRouter(Hash peer) { public void unshitlistRouter(Hash peer) {
if (peer == null) return; if (peer == null) return;
_log.info("Unshitlisting router " + peer.toBase64()); _log.info("Unshitlisting router " + peer.toBase64());
synchronized (_shitlist) { synchronized (_shitlist) {
_shitlist.remove(peer); _shitlist.remove(peer);
} }
} }
public boolean isShitlisted(Hash peer) { public boolean isShitlisted(Hash peer) {
Date shitlistDate = null; Date shitlistDate = null;
synchronized (_shitlist) { synchronized (_shitlist) {
shitlistDate = (Date)_shitlist.get(peer); shitlistDate = (Date)_shitlist.get(peer);
} }
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);
return false; return false;
} }
} }
public String renderStatusHTML() { public String renderStatusHTML() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("<h2>Shitlist</h2>"); buf.append("<h2>Shitlist</h2>");
Map shitlist = new HashMap(); Map shitlist = new HashMap();
synchronized (_shitlist) { synchronized (_shitlist) {
shitlist.putAll(_shitlist); shitlist.putAll(_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();
Date shitDate = (Date)shitlist.get(key); Date shitDate = (Date)shitlist.get(key);
if (shitDate.getTime() < limit) if (shitDate.getTime() < limit)
unshitlistRouter(key); unshitlistRouter(key);
else else
buf.append("<li><b>").append(key.toBase64()).append("</b> was shitlisted on ").append(shitDate).append("</li>\n"); buf.append("<li><b>").append(key.toBase64()).append("</b> was shitlisted on ").append(shitDate).append("</li>\n");
} }
buf.append("</ul>\n"); buf.append("</ul>\n");
return buf.toString(); return buf.toString();
} }
} }

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,12 +9,13 @@ 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
* component to some URL so that the network can be debugged more easily. By default * component to some URL so that the network can be debugged more easily. By default
* it does not submit any data or touch the message history file, but if the router * it does not submit any data or touch the message history file, but if the router
* has the line "router.submitHistory=true", it will send the file that the * has the line "router.submitHistory=true", it will send the file that the
* MessageHistory component is configured to write to once an hour, post it to * MessageHistory component is configured to write to once an hour, post it to
* http://i2p.net/cgi-bin/submitMessageHistory, and then delete that file * http://i2p.net/cgi-bin/submitMessageHistory, and then delete that file
* locally. This should only be used if the MessageHistory component is configured to * locally. This should only be used if the MessageHistory component is configured to
@ -22,14 +23,14 @@ 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;
/** /**
* router config param for whether we want to autosubmit (and delete) the * router config param for whether we want to autosubmit (and delete) the
* history data managed by MessageHistory * history data managed by MessageHistory
*/ */
public final static String PARAM_SUBMIT_DATA = "router.submitHistory"; public final static String PARAM_SUBMIT_DATA = "router.submitHistory";
/** default value for whether we autosubmit the data */ /** default value for whether we autosubmit the data */
public final static boolean DEFAULT_SUBMIT_DATA = true; public final static boolean DEFAULT_SUBMIT_DATA = true;
@ -38,14 +39,19 @@ 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();
} else { } else {
_log.debug("Not submitting data"); _log.debug("Not submitting data");
// if we didn't submit we can just requeue // if we didn't submit we can just requeue
requeue(getRequeueDelay()); requeue(getRequeueDelay());
} }
} }
/** /**
@ -53,64 +59,64 @@ public class SubmitMessageHistoryJob extends JobImpl {
* to do the actual submission, enqueueing a new submit job when its done * to do the actual submission, enqueueing a new submit job when its done
*/ */
private void submit() { private void submit() {
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");
t.setPriority(I2PThread.MIN_PRIORITY); t.setPriority(I2PThread.MIN_PRIORITY);
t.setDaemon(true); t.setDaemon(true);
t.start(); t.start();
} }
private void send(String filename) { private void send(String filename) {
String url = getURL(); String url = getURL();
try { try {
File dataFile = new File(filename); File dataFile = new File(filename);
if (!dataFile.exists() || !dataFile.canRead()) { if (!dataFile.exists() || !dataFile.canRead()) {
_log.warn("Unable to read the message data file [" + dataFile.getAbsolutePath() + "]"); _log.warn("Unable to read the message data file [" + dataFile.getAbsolutePath() + "]");
return; return;
} }
long size = dataFile.length(); long size = dataFile.length();
int expectedSend = 512; // 512 for HTTP overhead int expectedSend = 512; // 512 for HTTP overhead
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();
_log.debug("Submitted " + size + " bytes? " + sent + " and deleted? " + deleted); _log.debug("Submitted " + size + " bytes? " + sent + " and deleted? " + deleted);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error sending the data", ioe); _log.error("Error sending the data", ioe);
} }
} }
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
return str.trim(); return str.trim();
} }
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;
} else { } else {
_log.debug("History submit config specified [" + str + "]"); _log.debug("History submit config specified [" + str + "]");
} }
return Boolean.TRUE.toString().equals(str); return Boolean.TRUE.toString().equals(str);
} }
private long getRequeueDelay() { return DEFAULT_REQUEUE_DELAY; } private long getRequeueDelay() { return DEFAULT_REQUEUE_DELAY; }
public String getName() { return "Submit Message History"; } public String getName() { return "Submit Message History"; }

View File

@ -1,9 +1,9 @@
package net.i2p.router; package net.i2p.router;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -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,21 +51,22 @@ public class TunnelInfo extends DataStructureImpl {
private boolean _ready; private boolean _ready;
private boolean _wasEverReady; private boolean _wasEverReady;
public TunnelInfo() { public TunnelInfo(I2PAppContext context) {
setTunnelId(null); _context = context;
setThisHop(null); setTunnelId(null);
setNextHop(null); setThisHop(null);
setNextHopInfo(null); setNextHop(null);
_configurationKey = null; setNextHopInfo(null);
_verificationKey = null; _configurationKey = null;
_signingKey = null; _verificationKey = null;
_encryptionKey = null; _signingKey = null;
setDestination(null); _encryptionKey = null;
setSettings(null); setDestination(null);
_options = new Properties(); setSettings(null);
_ready = false; _options = new Properties();
_wasEverReady = false; _ready = false;
_created = Clock.getInstance().now(); _wasEverReady = false;
_created = _context.clock().now();
} }
public TunnelId getTunnelId() { return _id; } public TunnelId getTunnelId() { return _id; }
@ -81,34 +83,34 @@ public class TunnelInfo extends DataStructureImpl {
public TunnelConfigurationSessionKey getConfigurationKey() { return _configurationKey; } public TunnelConfigurationSessionKey getConfigurationKey() { return _configurationKey; }
public void setConfigurationKey(TunnelConfigurationSessionKey key) { _configurationKey = key; } public void setConfigurationKey(TunnelConfigurationSessionKey key) { _configurationKey = key; }
public void setConfigurationKey(SessionKey key) { public void setConfigurationKey(SessionKey key) {
TunnelConfigurationSessionKey tk = new TunnelConfigurationSessionKey(); TunnelConfigurationSessionKey tk = new TunnelConfigurationSessionKey();
tk.setKey(key); tk.setKey(key);
_configurationKey = tk; _configurationKey = tk;
} }
public TunnelSigningPublicKey getVerificationKey() { return _verificationKey; } public TunnelSigningPublicKey getVerificationKey() { return _verificationKey; }
public void setVerificationKey(TunnelSigningPublicKey key) { _verificationKey = key; } public void setVerificationKey(TunnelSigningPublicKey key) { _verificationKey = key; }
public void setVerificationKey(SigningPublicKey key) { public void setVerificationKey(SigningPublicKey key) {
TunnelSigningPublicKey tk = new TunnelSigningPublicKey(); TunnelSigningPublicKey tk = new TunnelSigningPublicKey();
tk.setKey(key); tk.setKey(key);
_verificationKey = tk; _verificationKey = tk;
} }
public TunnelSigningPrivateKey getSigningKey() { return _signingKey; } public TunnelSigningPrivateKey getSigningKey() { return _signingKey; }
public void setSigningKey(TunnelSigningPrivateKey key) { _signingKey = key; } public void setSigningKey(TunnelSigningPrivateKey key) { _signingKey = key; }
public void setSigningKey(SigningPrivateKey key) { public void setSigningKey(SigningPrivateKey key) {
TunnelSigningPrivateKey tk = new TunnelSigningPrivateKey(); TunnelSigningPrivateKey tk = new TunnelSigningPrivateKey();
tk.setKey(key); tk.setKey(key);
_signingKey = tk; _signingKey = tk;
} }
public TunnelSessionKey getEncryptionKey() { return _encryptionKey; } public TunnelSessionKey getEncryptionKey() { return _encryptionKey; }
public void setEncryptionKey(TunnelSessionKey key) { _encryptionKey = key; } public void setEncryptionKey(TunnelSessionKey key) { _encryptionKey = key; }
public void setEncryptionKey(SessionKey key) { public void setEncryptionKey(SessionKey key) {
TunnelSessionKey tk = new TunnelSessionKey(); TunnelSessionKey tk = new TunnelSessionKey();
tk.setKey(key); tk.setKey(key);
_encryptionKey = tk; _encryptionKey = tk;
} }
public Destination getDestination() { return _destination; } public Destination getDestination() { return _destination; }
@ -120,17 +122,17 @@ public class TunnelInfo extends DataStructureImpl {
public Set getPropertyNames() { return new HashSet(_options.keySet()); } public Set getPropertyNames() { return new HashSet(_options.keySet()); }
public TunnelSettings getSettings() { return _settings; } public TunnelSettings getSettings() { return _settings; }
public void setSettings(TunnelSettings settings) { _settings = settings; } public void setSettings(TunnelSettings settings) { _settings = settings; }
/** /**
* Have all of the routers in this tunnel confirmed participation, and we're ok to * Have all of the routers in this tunnel confirmed participation, and we're ok to
* start sending messages through this tunnel? * start sending messages through this tunnel?
*/ */
public boolean getIsReady() { return _ready; } public boolean getIsReady() { return _ready; }
public void setIsReady(boolean ready) { public void setIsReady(boolean ready) {
_ready = ready; _ready = ready;
if (ready) if (ready)
_wasEverReady = true; _wasEverReady = true;
} }
/** /**
* true if this tunnel was ever working (aka rebuildable) * true if this tunnel was ever working (aka rebuildable)
@ -145,204 +147,204 @@ public class TunnelInfo extends DataStructureImpl {
* *
*/ */
public final int getLength() { public final int getLength() {
int len = 0; int len = 0;
TunnelInfo info = this; TunnelInfo info = this;
while (info != null) { while (info != null) {
info = info.getNextHopInfo(); info = info.getNextHopInfo();
len++; len++;
} }
return len; return len;
} }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
_options = DataHelper.readProperties(in); _options = DataHelper.readProperties(in);
Boolean includeDest = DataHelper.readBoolean(in); Boolean includeDest = DataHelper.readBoolean(in);
if (includeDest.booleanValue()) { if (includeDest.booleanValue()) {
_destination = new Destination(); _destination = new Destination();
_destination.readBytes(in); _destination.readBytes(in);
} else { } else {
_destination = null; _destination = null;
} }
Boolean includeThis = DataHelper.readBoolean(in); Boolean includeThis = DataHelper.readBoolean(in);
if (includeThis.booleanValue()) { if (includeThis.booleanValue()) {
_thisHop = new Hash(); _thisHop = new Hash();
_thisHop.readBytes(in); _thisHop.readBytes(in);
} else { } else {
_thisHop = null; _thisHop = null;
} }
Boolean includeNext = DataHelper.readBoolean(in); Boolean includeNext = DataHelper.readBoolean(in);
if (includeNext.booleanValue()) { if (includeNext.booleanValue()) {
_nextHop = new Hash(); _nextHop = new Hash();
_nextHop.readBytes(in); _nextHop.readBytes(in);
} else { } else {
_nextHop = null; _nextHop = null;
} }
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;
} }
_id = new TunnelId(); _id = new TunnelId();
_id.readBytes(in); _id.readBytes(in);
Boolean includeConfigKey = DataHelper.readBoolean(in); Boolean includeConfigKey = DataHelper.readBoolean(in);
if (includeConfigKey.booleanValue()) { if (includeConfigKey.booleanValue()) {
_configurationKey = new TunnelConfigurationSessionKey(); _configurationKey = new TunnelConfigurationSessionKey();
_configurationKey.readBytes(in); _configurationKey.readBytes(in);
} else { } else {
_configurationKey = null; _configurationKey = null;
} }
Boolean includeEncryptionKey = DataHelper.readBoolean(in); Boolean includeEncryptionKey = DataHelper.readBoolean(in);
if (includeEncryptionKey.booleanValue()) { if (includeEncryptionKey.booleanValue()) {
_encryptionKey = new TunnelSessionKey(); _encryptionKey = new TunnelSessionKey();
_encryptionKey.readBytes(in); _encryptionKey.readBytes(in);
} else { } else {
_encryptionKey = null; _encryptionKey = null;
} }
Boolean includeSigningKey = DataHelper.readBoolean(in); Boolean includeSigningKey = DataHelper.readBoolean(in);
if (includeSigningKey.booleanValue()) { if (includeSigningKey.booleanValue()) {
_signingKey = new TunnelSigningPrivateKey(); _signingKey = new TunnelSigningPrivateKey();
_signingKey.readBytes(in); _signingKey.readBytes(in);
} else { } else {
_signingKey = null; _signingKey = null;
} }
Boolean includeVerificationKey = DataHelper.readBoolean(in); Boolean includeVerificationKey = DataHelper.readBoolean(in);
if (includeVerificationKey.booleanValue()) { if (includeVerificationKey.booleanValue()) {
_verificationKey = new TunnelSigningPublicKey(); _verificationKey = new TunnelSigningPublicKey();
_verificationKey.readBytes(in); _verificationKey.readBytes(in);
} 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)
setIsReady(ready.booleanValue()); setIsReady(ready.booleanValue());
} }
public void writeBytes(OutputStream out) throws DataFormatException, IOException { public void writeBytes(OutputStream out) throws DataFormatException, IOException {
if (_id == null) throw new DataFormatException("Invalid tunnel ID: " + _id); if (_id == null) throw new DataFormatException("Invalid tunnel ID: " + _id);
if (_options == null) throw new DataFormatException("Options are null"); if (_options == null) throw new DataFormatException("Options are null");
if (_settings == null) throw new DataFormatException("Settings are null"); if (_settings == null) throw new DataFormatException("Settings are null");
// everything else is optional in the serialization // everything else is optional in the serialization
DataHelper.writeProperties(out, _options); DataHelper.writeProperties(out, _options);
if (_destination != null) { if (_destination != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_destination.writeBytes(out); _destination.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
if (_thisHop != null) { if (_thisHop != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_thisHop.writeBytes(out); _thisHop.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
if (_nextHop != null) { if (_nextHop != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_nextHop.writeBytes(out); _nextHop.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
if (_nextHopInfo != null) { if (_nextHopInfo != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_nextHopInfo.writeBytes(out); _nextHopInfo.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
_id.writeBytes(out); _id.writeBytes(out);
if (_configurationKey != null) { if (_configurationKey != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_configurationKey.writeBytes(out); _configurationKey.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
if (_encryptionKey != null) { if (_encryptionKey != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_encryptionKey.writeBytes(out); _encryptionKey.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
if (_signingKey != null) { if (_signingKey != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_signingKey.writeBytes(out); _signingKey.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
if (_verificationKey != null) { if (_verificationKey != null) {
DataHelper.writeBoolean(out, Boolean.TRUE); DataHelper.writeBoolean(out, Boolean.TRUE);
_verificationKey.writeBytes(out); _verificationKey.writeBytes(out);
} else { } else {
DataHelper.writeBoolean(out, Boolean.FALSE); DataHelper.writeBoolean(out, Boolean.FALSE);
} }
_settings.writeBytes(out); _settings.writeBytes(out);
DataHelper.writeBoolean(out, new Boolean(_ready)); DataHelper.writeBoolean(out, new Boolean(_ready));
} }
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
buf.append("[Tunnel ").append(_id.getTunnelId()); buf.append("[Tunnel ").append(_id.getTunnelId());
TunnelInfo cur = this; TunnelInfo cur = this;
int i = 0; int i = 0;
while (cur != null) { while (cur != null) {
buf.append("\n*Hop ").append(i).append(": ").append(cur.getThisHop()); buf.append("\n*Hop ").append(i).append(": ").append(cur.getThisHop());
if (cur.getEncryptionKey() != null) if (cur.getEncryptionKey() != null)
buf.append("\n Encryption key: ").append(cur.getEncryptionKey()); buf.append("\n Encryption key: ").append(cur.getEncryptionKey());
if (cur.getSigningKey() != null) if (cur.getSigningKey() != null)
buf.append("\n Signing key: ").append(cur.getSigningKey()); buf.append("\n Signing key: ").append(cur.getSigningKey());
if (cur.getVerificationKey() != null) if (cur.getVerificationKey() != null)
buf.append("\n Verification key: ").append(cur.getVerificationKey()); buf.append("\n Verification key: ").append(cur.getVerificationKey());
if (cur.getDestination() != null) if (cur.getDestination() != null)
buf.append("\n Destination: ").append(cur.getDestination().calculateHash().toBase64()); buf.append("\n Destination: ").append(cur.getDestination().calculateHash().toBase64());
if (cur.getNextHop() != null) if (cur.getNextHop() != null)
buf.append("\n Next: ").append(cur.getNextHop()); buf.append("\n Next: ").append(cur.getNextHop());
if (cur.getSettings() == null) if (cur.getSettings() == null)
buf.append("\n Expiration: ").append("none"); buf.append("\n Expiration: ").append("none");
else else
buf.append("\n Expiration: ").append(new Date(cur.getSettings().getExpiration())); buf.append("\n Expiration: ").append(new Date(cur.getSettings().getExpiration()));
buf.append("\n Ready: ").append(getIsReady()); buf.append("\n Ready: ").append(getIsReady());
cur = cur.getNextHopInfo(); cur = cur.getNextHopInfo();
i++; i++;
} }
buf.append("]"); buf.append("]");
return buf.toString(); return buf.toString();
} }
public int hashCode() { public int hashCode() {
int rv = 0; int rv = 0;
rv = 7*rv + DataHelper.hashCode(_options); rv = 7*rv + DataHelper.hashCode(_options);
rv = 7*rv + DataHelper.hashCode(_destination); rv = 7*rv + DataHelper.hashCode(_destination);
rv = 7*rv + DataHelper.hashCode(_nextHop); rv = 7*rv + DataHelper.hashCode(_nextHop);
rv = 7*rv + DataHelper.hashCode(_thisHop); rv = 7*rv + DataHelper.hashCode(_thisHop);
rv = 7*rv + DataHelper.hashCode(_id); rv = 7*rv + DataHelper.hashCode(_id);
rv = 7*rv + DataHelper.hashCode(_configurationKey); rv = 7*rv + DataHelper.hashCode(_configurationKey);
rv = 7*rv + DataHelper.hashCode(_encryptionKey); rv = 7*rv + DataHelper.hashCode(_encryptionKey);
rv = 7*rv + DataHelper.hashCode(_signingKey); rv = 7*rv + DataHelper.hashCode(_signingKey);
rv = 7*rv + DataHelper.hashCode(_verificationKey); rv = 7*rv + DataHelper.hashCode(_verificationKey);
rv = 7*rv + DataHelper.hashCode(_settings); rv = 7*rv + DataHelper.hashCode(_settings);
rv = 7*rv + (_ready ? 0 : 1); rv = 7*rv + (_ready ? 0 : 1);
return rv; return rv;
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( (obj != null) && (obj instanceof TunnelInfo) ) { if ( (obj != null) && (obj instanceof TunnelInfo) ) {
TunnelInfo info = (TunnelInfo)obj; TunnelInfo info = (TunnelInfo)obj;
return DataHelper.eq(getConfigurationKey(), info.getConfigurationKey()) && return DataHelper.eq(getConfigurationKey(), info.getConfigurationKey()) &&
DataHelper.eq(getDestination(), info.getDestination()) && DataHelper.eq(getDestination(), info.getDestination()) &&
getIsReady() == info.getIsReady() && getIsReady() == info.getIsReady() &&
DataHelper.eq(getEncryptionKey(), info.getEncryptionKey()) && DataHelper.eq(getEncryptionKey(), info.getEncryptionKey()) &&
DataHelper.eq(getNextHop(), info.getNextHop()) && DataHelper.eq(getNextHop(), info.getNextHop()) &&
DataHelper.eq(getNextHopInfo(), info.getNextHopInfo()) && DataHelper.eq(getNextHopInfo(), info.getNextHopInfo()) &&
DataHelper.eq(getSettings(), info.getSettings()) && DataHelper.eq(getSettings(), info.getSettings()) &&
DataHelper.eq(getSigningKey(), info.getSigningKey()) && DataHelper.eq(getSigningKey(), info.getSigningKey()) &&
DataHelper.eq(getThisHop(), info.getThisHop()) && DataHelper.eq(getThisHop(), info.getThisHop()) &&
DataHelper.eq(getTunnelId(), info.getTunnelId()) && DataHelper.eq(getTunnelId(), info.getTunnelId()) &&
DataHelper.eq(getVerificationKey(), info.getVerificationKey()) && DataHelper.eq(getVerificationKey(), info.getVerificationKey()) &&
DataHelper.eq(_options, info._options); DataHelper.eq(_options, info._options);
} else { } else {
return false; return false;
} }
} }
} }

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

@ -1,9 +1,9 @@
package net.i2p.router; package net.i2p.router;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -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,18 +34,19 @@ public class TunnelSettings extends DataStructureImpl {
private long _expiration; private long _expiration;
private long _created; private long _created;
public TunnelSettings() { public TunnelSettings(I2PAppContext context) {
_depth = 0; _context = context;
_msgsPerMinuteAvg = 0; _depth = 0;
_msgsPerMinutePeak = 0; _msgsPerMinuteAvg = 0;
_bytesPerMinuteAvg = 0; _msgsPerMinutePeak = 0;
_bytesPerMinutePeak = 0; _bytesPerMinuteAvg = 0;
_includeDummy = false; _bytesPerMinutePeak = 0;
_reorder = false; _includeDummy = false;
_expiration = 0; _reorder = false;
_created = Clock.getInstance().now(); _expiration = 0;
_created = _context.clock().now();
} }
public int getDepth() { return _depth; } public int getDepth() { return _depth; }
public void setDepth(int depth) { _depth = depth; } public void setDepth(int depth) { _depth = depth; }
public long getMessagesPerMinuteAverage() { return _msgsPerMinuteAvg; } public long getMessagesPerMinuteAverage() { return _msgsPerMinuteAvg; }
@ -64,71 +66,71 @@ public class TunnelSettings extends DataStructureImpl {
public long getCreated() { return _created; } public long getCreated() { return _created; }
public void readBytes(InputStream in) throws DataFormatException, IOException { public void readBytes(InputStream in) throws DataFormatException, IOException {
Boolean b = DataHelper.readBoolean(in); Boolean b = DataHelper.readBoolean(in);
if (b == null) throw new DataFormatException("Null includeDummy boolean value"); if (b == null) throw new DataFormatException("Null includeDummy boolean value");
_includeDummy = b.booleanValue(); _includeDummy = b.booleanValue();
b = DataHelper.readBoolean(in); b = DataHelper.readBoolean(in);
if (b == null) throw new DataFormatException("Null reorder boolean value"); if (b == null) throw new DataFormatException("Null reorder boolean value");
_reorder = b.booleanValue(); _reorder = b.booleanValue();
_depth = (int)DataHelper.readLong(in, 1); _depth = (int)DataHelper.readLong(in, 1);
_bytesPerMinuteAvg = DataHelper.readLong(in, 4); _bytesPerMinuteAvg = DataHelper.readLong(in, 4);
_bytesPerMinutePeak = DataHelper.readLong(in, 4); _bytesPerMinutePeak = DataHelper.readLong(in, 4);
Date exp = DataHelper.readDate(in); Date exp = DataHelper.readDate(in);
if (exp == null) if (exp == null)
_expiration = 0; _expiration = 0;
else else
_expiration = exp.getTime(); _expiration = exp.getTime();
_msgsPerMinuteAvg = DataHelper.readLong(in, 4); _msgsPerMinuteAvg = DataHelper.readLong(in, 4);
_msgsPerMinutePeak = DataHelper.readLong(in, 4); _msgsPerMinutePeak = DataHelper.readLong(in, 4);
Date created = DataHelper.readDate(in); Date created = DataHelper.readDate(in);
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 {
DataHelper.writeBoolean(out, _includeDummy ? Boolean.TRUE : Boolean.FALSE); DataHelper.writeBoolean(out, _includeDummy ? Boolean.TRUE : Boolean.FALSE);
DataHelper.writeBoolean(out, _reorder ? Boolean.TRUE : Boolean.FALSE); DataHelper.writeBoolean(out, _reorder ? Boolean.TRUE : Boolean.FALSE);
DataHelper.writeLong(out, 1, _depth); DataHelper.writeLong(out, 1, _depth);
DataHelper.writeLong(out, 4, _bytesPerMinuteAvg); DataHelper.writeLong(out, 4, _bytesPerMinuteAvg);
DataHelper.writeLong(out, 4, _bytesPerMinutePeak); DataHelper.writeLong(out, 4, _bytesPerMinutePeak);
if (_expiration <= 0) if (_expiration <= 0)
DataHelper.writeDate(out, new Date(0)); DataHelper.writeDate(out, new Date(0));
else else
DataHelper.writeDate(out, new Date(_expiration)); DataHelper.writeDate(out, new Date(_expiration));
DataHelper.writeLong(out, 4, _msgsPerMinuteAvg); DataHelper.writeLong(out, 4, _msgsPerMinuteAvg);
DataHelper.writeLong(out, 4, _msgsPerMinutePeak); DataHelper.writeLong(out, 4, _msgsPerMinutePeak);
DataHelper.writeDate(out, new Date(_created)); DataHelper.writeDate(out, new Date(_created));
} }
public int hashCode() { public int hashCode() {
int rv = 0; int rv = 0;
rv += _includeDummy ? 100 : 0; rv += _includeDummy ? 100 : 0;
rv += _reorder ? 50 : 0; rv += _reorder ? 50 : 0;
rv += _depth; rv += _depth;
rv += _bytesPerMinuteAvg; rv += _bytesPerMinuteAvg;
rv += _bytesPerMinutePeak; rv += _bytesPerMinutePeak;
rv += _expiration; rv += _expiration;
rv += _msgsPerMinuteAvg; rv += _msgsPerMinuteAvg;
rv += _msgsPerMinutePeak; rv += _msgsPerMinutePeak;
return rv; return rv;
} }
public boolean equals(Object obj) { public boolean equals(Object obj) {
if ( (obj != null) && (obj instanceof TunnelSettings) ) { if ( (obj != null) && (obj instanceof TunnelSettings) ) {
TunnelSettings settings = (TunnelSettings)obj; TunnelSettings settings = (TunnelSettings)obj;
return settings.getBytesPerMinuteAverage() == getBytesPerMinuteAverage() && return settings.getBytesPerMinuteAverage() == getBytesPerMinuteAverage() &&
settings.getBytesPerMinutePeak() == getBytesPerMinutePeak() && settings.getBytesPerMinutePeak() == getBytesPerMinutePeak() &&
settings.getDepth() == getDepth() && settings.getDepth() == getDepth() &&
settings.getExpiration() == getExpiration() && settings.getExpiration() == getExpiration() &&
settings.getIncludeDummy() == getIncludeDummy() && settings.getIncludeDummy() == getIncludeDummy() &&
settings.getMessagesPerMinuteAverage() == getMessagesPerMinuteAverage() && settings.getMessagesPerMinuteAverage() == getMessagesPerMinuteAverage() &&
settings.getMessagesPerMinutePeak() == getMessagesPerMinutePeak() && settings.getMessagesPerMinutePeak() == getMessagesPerMinutePeak() &&
settings.getReorder() == getReorder(); settings.getReorder() == getReorder();
} else { } else {
return false; return false;
} }
} }
} }

View File

@ -1,9 +1,9 @@
package net.i2p.router.admin; package net.i2p.router.admin;
/* /*
* free (adj.): unencumbered; not under the control of others * free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain * Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied. * with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat * It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk. * your children, but it might. Use at your own risk.
* *
*/ */
@ -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,15 +23,18 @@ 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) {
_port = port; _context = context;
_running = false; _log = context.logManager().getLog(AdminListener.class);
_port = port;
_running = false;
} }
public void setPort(int port) { _port = port; } public void setPort(int port) { _port = port; }
@ -39,50 +43,50 @@ public class AdminListener implements Runnable {
/** max time to bind */ /** max time to bind */
private final static int MAX_FAIL_DELAY = 5*60*1000; private final static int MAX_FAIL_DELAY = 5*60*1000;
/** /**
* Start up the socket listener, listens for connections, and * Start up the socket listener, listens for connections, and
* fires those connections off via {@link #runConnection runConnection}. * fires those connections off via {@link #runConnection runConnection}.
* This only returns if the socket cannot be opened or there is a catastrophic * This only returns if the socket cannot be opened or there is a catastrophic
* failure. * failure.
* *
*/ */
public void startup() { public void startup() {
_running = true; _running = true;
int curDelay = 0; int curDelay = 0;
while ( (_running) && (curDelay < MAX_FAIL_DELAY) ) { while ( (_running) && (curDelay < MAX_FAIL_DELAY) ) {
try { try {
_log.info("Starting up listening for connections on port " + _port); _log.info("Starting up listening for connections on port " + _port);
_socket = new ServerSocket(_port); _socket = new ServerSocket(_port);
curDelay = 0; curDelay = 0;
while (_running) { while (_running) {
try { try {
Socket socket = _socket.accept(); Socket socket = _socket.accept();
_log.debug("Connection received"); _log.debug("Connection received");
runConnection(socket); runConnection(socket);
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Server error accepting", ioe); _log.error("Server error accepting", ioe);
} catch (Throwable t) { } catch (Throwable t) {
_log.error("Fatal error running client listener - killing the thread!", t); _log.error("Fatal error running client listener - killing the thread!", t);
return; return;
} }
} }
} catch (IOException ioe) { } catch (IOException ioe) {
_log.error("Error listening on port " + _port, ioe); _log.error("Error listening on port " + _port, ioe);
} }
if (_socket != null) { if (_socket != null) {
try { _socket.close(); } catch (IOException ioe) {} try { _socket.close(); } catch (IOException ioe) {}
_socket = null; _socket = null;
} }
_log.error("Error listening, waiting " + _nextFailDelay + "ms before we try again"); _log.error("Error listening, waiting " + _nextFailDelay + "ms before we try again");
try { Thread.sleep(_nextFailDelay); } catch (InterruptedException ie) {} try { Thread.sleep(_nextFailDelay); } catch (InterruptedException ie) {}
curDelay += _nextFailDelay; curDelay += _nextFailDelay;
_nextFailDelay *= 5; _nextFailDelay *= 5;
} }
_log.error("CANCELING ADMIN LISTENER. delay = " + curDelay, new Exception("ADMIN LISTENER cancelled!!!")); _log.error("CANCELING ADMIN LISTENER. delay = " + curDelay, new Exception("ADMIN LISTENER cancelled!!!"));
_running = false; _running = false;
} }
/** /**
@ -90,20 +94,20 @@ 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);
t.setDaemon(true); t.setDaemon(true);
t.start(); t.start();
} }
public void shutdown() { public void shutdown() {
_running = false; _running = false;
if (_socket != null) try { if (_socket != null) try {
_socket.close(); _socket.close();
_socket = null; _socket = null;
} catch (IOException ioe) {} } catch (IOException ioe) {}
} }
public void run() { startup(); } public void run() { startup(); }
} }

View File

@ -4,47 +4,52 @@ 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() {
if (_listener != null) { if (_listener != null) {
_log.info("Shutting down admin listener"); _log.info("Shutting down admin listener");
_listener.shutdown(); _listener.shutdown();
_listener = null; _listener = null;
} }
} }
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);
port = val; port = val;
} catch (NumberFormatException nfe) { } catch (NumberFormatException nfe) {
_log.warn("Invalid admin port specified [" + str + "]", nfe); _log.warn("Invalid admin port specified [" + str + "]", nfe);
} }
} }
_log.info("Starting up admin listener on port " + port); _log.info("Starting up admin listener on port " + port);
startup(port); startup(port);
} }
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);
t.setPriority(Thread.MIN_PRIORITY); t.setPriority(Thread.MIN_PRIORITY);
t.start(); t.start();
} }
} }

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