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

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

View File

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

View File

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

View File

@@ -32,6 +32,7 @@ import net.i2p.data.i2cp.SendMessageMessage;
import net.i2p.data.i2cp.SessionConfig;
import net.i2p.util.Log;
import net.i2p.util.RandomSource;
import net.i2p.I2PAppContext;
/**
* Produce the various messages the session needs to send to the router.
@@ -41,7 +42,12 @@ import net.i2p.util.RandomSource;
class I2CPMessageProducer {
private final static Log _log = new Log(I2CPMessageProducer.class);
private final static RandomSource _rand = RandomSource.getInstance();
private I2PAppContext _context;
public I2CPMessageProducer(I2PAppContext context) {
_context = context;
}
/**
* Send all the messages that a client needs to send to a router to establish
* a new session.
@@ -102,7 +108,7 @@ class I2CPMessageProducer {
Payload data = new Payload();
// randomize padding
int size = payload.length + RandomSource.getInstance().nextInt(1024);
byte encr[] = ElGamalAESEngine.encrypt(payload, dest.getPublicKey(), key, tags, tag, newKey, size);
byte encr[] = _context.elGamalAESEngine().encrypt(payload, dest.getPublicKey(), key, tags, tag, newKey, size);
// yes, in an intelligent component, newTags would be queued for confirmation along with key, and
// generateNewTags would only generate tags if necessary

View File

@@ -22,6 +22,7 @@ import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.I2PAppContext;
/**
* Base client implementation
@@ -70,7 +71,13 @@ class I2PClientImpl implements I2PClient {
*
*/
public I2PSession createSession(InputStream destKeyStream, Properties options) throws I2PSessionException {
//return new I2PSessionImpl(destKeyStream, options); // not thread safe
return new I2PSessionImpl2(destKeyStream, options); // thread safe
return createSession(I2PAppContext.getGlobalContext(), destKeyStream, options);
}
/**
* Create a new session (though do not connect it yet)
*
*/
public I2PSession createSession(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException {
return new I2PSessionImpl2(context, destKeyStream, options); // thread safe
}
}

View File

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

View File

@@ -39,6 +39,7 @@ import net.i2p.data.i2cp.SessionId;
import net.i2p.util.Clock;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/**
* Implementation of an I2P session running over TCP. This class is NOT thread safe -
@@ -47,7 +48,7 @@ import net.i2p.util.Log;
* @author jrandom
*/
abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessageEventListener {
private final static Log _log = new Log(I2PSessionImpl.class);
private Log _log;
/** who we are */
private Destination _myDestination;
/** private key for decryption */
@@ -79,6 +80,11 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected I2CPMessageProducer _producer;
/** map of integer --> MessagePayloadMessage */
Map _availableMessages;
protected I2PClientMessageHandlerMap _handlerMap;
/** used to seperate things out so we can get rid of singletons */
protected I2PAppContext _context;
/** MessageStatusMessage status from the most recent send that hasn't been consumed */
private List _receivedStatus;
@@ -108,9 +114,12 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
*
* @throws I2PSessionException if there is a problem loading the private keys or
*/
public I2PSessionImpl(InputStream destKeyStream, Properties options) throws I2PSessionException {
public I2PSessionImpl(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException {
_context = context;
_log = context.logManager().getLog(I2PSessionImpl.class);
_handlerMap = new I2PClientMessageHandlerMap(context);
_closed = true;
_producer = new I2CPMessageProducer();
_producer = new I2CPMessageProducer(context);
_availableMessages = new HashMap();
try {
readDestination(destKeyStream);
@@ -139,13 +148,13 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
_portNum = Integer.parseInt(portNum);
} catch (NumberFormatException nfe) {
if (_log.shouldLog(Log.WARN))
_log.warn("Invalid port number specified, defaulting to "
+ TestServer.LISTEN_PORT, nfe);
_log.warn("Invalid port number specified, defaulting to "
+ TestServer.LISTEN_PORT, nfe);
_portNum = TestServer.LISTEN_PORT;
}
}
private static Properties filter(Properties options) {
private Properties filter(Properties options) {
Properties rv = new Properties();
for (Iterator iter = options.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
@@ -212,7 +221,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
*/
public void connect() throws I2PSessionException {
_closed = false;
long startConnect = Clock.getInstance().now();
long startConnect = _context.clock().now();
try {
if (_log.shouldLog(Log.DEBUG)) _log.debug("connect begin to " + _hostname + ":" + _portNum);
_socket = new Socket(_hostname, _portNum);
@@ -251,7 +260,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
}
}
long connected = Clock.getInstance().now();
long connected = _context.clock().now();
if (_log.shouldLog(Log.INFO))
_log.info("Lease set created with inbound tunnels after "
+ (connected - startConnect)
@@ -339,7 +348,7 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
*
*/
public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
I2CPMessageHandler handler = I2PClientMessageHandlerMap.getHandler(message.getType());
I2CPMessageHandler handler = _handlerMap.getHandler(message.getType());
if (handler == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unknown message or unhandleable message received: type = "

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -8,11 +8,21 @@
package net.i2p.client.naming;
import net.i2p.data.Destination;
import net.i2p.I2PAppContext;
/**
* A Dummy naming service that can only handle base64 destinations.
*/
class DummyNamingService extends NamingService {
/**
* The naming service should only be constructed and accessed through the
* application context. This constructor should only be used by the
* appropriate application context itself.
*
*/
protected DummyNamingService(I2PAppContext context) { super(context); }
private DummyNamingService() { super(null); }
public Destination lookup(String hostname) {
return lookupBase64(hostname);
}

View File

@@ -14,12 +14,22 @@ import java.util.Properties;
import net.i2p.data.Destination;
import net.i2p.util.Log;
import net.i2p.I2PAppContext;
/**
* A naming service based on the "hosts.txt" file.
*/
public class HostsTxtNamingService extends NamingService {
/**
* The naming service should only be constructed and accessed through the
* application context. This constructor should only be used by the
* appropriate application context itself.
*
*/
protected HostsTxtNamingService(I2PAppContext context) { super(context); }
private HostsTxtNamingService() { super(null); }
/**
* If this system property is specified, the tunnel will read the
* given file for hostname=destKey values when resolving names
@@ -35,7 +45,7 @@ public class HostsTxtNamingService extends NamingService {
// Try to look it up in hosts.txt
// Reload file each time to catch changes.
// (and it's easier :P
String hostsfile = System.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE);
String hostsfile = _context.getProperty(PROP_HOSTS_FILE, DEFAULT_HOSTS_FILE);
Properties hosts = new Properties();
FileInputStream fis = null;
try {

View File

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