propagate from branch 'i2p.i2p.zzz.test' (head f19c9c4ae55d6ae82d6c028a06c0fae886da2527)

to branch 'i2p.i2p' (head 78d8ece1514216315644bbef224c62e1e9fbe370)
This commit is contained in:
zzz
2009-02-27 21:25:04 +00:00
60 changed files with 3344 additions and 189 deletions

View File

@ -23,6 +23,7 @@ import net.i2p.crypto.SessionKeyManager;
import net.i2p.data.RoutingKeyGenerator;
import net.i2p.stat.StatManager;
import net.i2p.util.Clock;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.FortunaRandomSource;
import net.i2p.util.KeyRing;
import net.i2p.util.LogManager;
@ -94,6 +95,7 @@ public class I2PAppContext {
private volatile boolean _randomInitialized;
private volatile boolean _keyGeneratorInitialized;
protected volatile boolean _keyRingInitialized; // used in RouterContext
private Set<Runnable> _shutdownTasks;
/**
@ -152,6 +154,7 @@ public class I2PAppContext {
_elGamalAESEngineInitialized = false;
_logManagerInitialized = false;
_keyRingInitialized = false;
_shutdownTasks = new ConcurrentHashSet(0);
}
/**
@ -557,4 +560,13 @@ public class I2PAppContext {
_randomInitialized = true;
}
}
public void addShutdownTask(Runnable task) {
_shutdownTasks.add(task);
}
public Set<Runnable> getShutdownTasks() {
return new HashSet(_shutdownTasks);
}
}

View File

@ -77,6 +77,6 @@ class I2PClientImpl implements I2PClient {
*
*/
public I2PSession createSession(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException {
return new I2PSessionImpl2(context, destKeyStream, options); // thread safe
return new I2PSessionMuxedImpl(context, destKeyStream, options); // thread safe and muxed
}
}

View File

@ -40,6 +40,8 @@ public interface I2PSession {
*/
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException;
/** See I2PSessionMuxedImpl for details */
public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException;
/**
* Like sendMessage above, except the key used and the tags sent are exposed to the
@ -71,6 +73,12 @@ public interface I2PSession {
public boolean sendMessage(Destination dest, byte[] payload, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent) throws I2PSessionException;
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire) throws I2PSessionException;
/** See I2PSessionMuxedImpl for details */
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
int proto, int fromport, int toport) throws I2PSessionException;
/** See I2PSessionMuxedImpl for details */
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
int proto, int fromport, int toport) throws I2PSessionException;
/** Receive a message that the router has notified the client about, returning
* the payload.
@ -134,4 +142,18 @@ public interface I2PSession {
*
*/
public Destination lookupDest(Hash h) throws I2PSessionException;
/** See I2PSessionMuxedImpl for details */
public void addSessionListener(I2PSessionListener lsnr, int proto, int port);
/** See I2PSessionMuxedImpl for details */
public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port);
/** See I2PSessionMuxedImpl for details */
public void removeListener(int proto, int port);
public static final int PORT_ANY = 0;
public static final int PORT_UNSPECIFIED = 0;
public static final int PROTO_ANY = 0;
public static final int PROTO_UNSPECIFIED = 0;
public static final int PROTO_STREAMING = 6;
public static final int PROTO_DATAGRAM = 17;
}

View File

@ -0,0 +1,135 @@
package net.i2p.client;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
/*
* public domain
*/
/**
* Implement multiplexing with a 1-byte 'protocol' and a two-byte 'port'.
* Listeners register with either addListener() or addMuxedListener(),
* depending on whether they want to hear about the
* protocol, from port, and to port for every received message.
*
* This only calls one listener, not all that apply.
*
* @author zzz
*/
public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
private Log _log;
private Map<Integer, I2PSessionMuxedListener> _listeners;
public I2PSessionDemultiplexer(I2PAppContext ctx) {
_log = ctx.logManager().getLog(I2PSessionDemultiplexer.class);
_listeners = new ConcurrentHashMap();
}
/** unused */
public void messageAvailable(I2PSession session, int msgId, long size) {}
public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport ) {
I2PSessionMuxedListener l = findListener(proto, toport);
if (l != null)
l.messageAvailable(session, msgId, size, proto, fromport, toport);
else {
// no listener, throw it out
_log.error("No listener found for proto: " + proto + " port: " + toport + "msg id: " + msgId +
" from pool of " + _listeners.size() + " listeners");
try {
session.receiveMessage(msgId);
} catch (I2PSessionException ise) {}
}
}
public void reportAbuse(I2PSession session, int severity) {
for (I2PSessionMuxedListener l : _listeners.values())
l.reportAbuse(session, severity);
}
public void disconnected(I2PSession session) {
for (I2PSessionMuxedListener l : _listeners.values())
l.disconnected(session);
}
public void errorOccurred(I2PSession session, String message, Throwable error) {
for (I2PSessionMuxedListener l : _listeners.values())
l.errorOccurred(session, message, error);
}
/**
* For those that don't need to hear about the protocol and ports
* in messageAvailable()
* (Streaming lib)
*/
public void addListener(I2PSessionListener l, int proto, int port) {
_listeners.put(key(proto, port), new NoPortsListener(l));
}
/**
* For those that do care
* UDP perhaps
*/
public void addMuxedListener(I2PSessionMuxedListener l, int proto, int port) {
_listeners.put(key(proto, port), l);
}
public void removeListener(int proto, int port) {
_listeners.remove(key(proto, port));
}
/** find the one listener that most specifically matches the request */
private I2PSessionMuxedListener findListener(int proto, int port) {
I2PSessionMuxedListener rv = getListener(proto, port);
if (rv != null) return rv;
if (port != I2PSession.PORT_ANY) { // try any port
rv = getListener(proto, I2PSession.PORT_ANY);
if (rv != null) return rv;
}
if (proto != I2PSession.PROTO_ANY) { // try any protocol
rv = getListener(I2PSession.PROTO_ANY, port);
if (rv != null) return rv;
}
if (proto != I2PSession.PROTO_ANY && port != I2PSession.PORT_ANY) { // try default
rv = getListener(I2PSession.PROTO_ANY, I2PSession.PORT_ANY);
}
return rv;
}
private I2PSessionMuxedListener getListener(int proto, int port) {
return _listeners.get(key(proto, port));
}
private Integer key(int proto, int port) {
return Integer.valueOf(((port << 8) & 0xffff00) | proto);
}
/** for those that don't care about proto and ports */
private static class NoPortsListener implements I2PSessionMuxedListener {
private I2PSessionListener _l;
public NoPortsListener(I2PSessionListener l) {
_l = l;
}
public void messageAvailable(I2PSession session, int msgId, long size) {
throw new IllegalArgumentException("no");
}
public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport) {
_l.messageAvailable(session, msgId, size);
}
public void reportAbuse(I2PSession session, int severity) {
_l.reportAbuse(session, severity);
}
public void disconnected(I2PSession session) {
_l.disconnected(session);
}
public void errorOccurred(I2PSession session, String message, Throwable error) {
_l.errorOccurred(session, message, error);
}
}
}

View File

@ -77,12 +77,12 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
protected OutputStream _out;
/** who we send events to */
private I2PSessionListener _sessionListener;
protected I2PSessionListener _sessionListener;
/** class that generates new messages */
protected I2CPMessageProducer _producer;
/** map of Long --> MessagePayloadMessage */
private Map<Long, MessagePayloadMessage> _availableMessages;
protected Map<Long, MessagePayloadMessage> _availableMessages;
protected I2PClientMessageHandlerMap _handlerMap;
@ -366,14 +366,14 @@ abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2CPMessa
}
SimpleScheduler.getInstance().addEvent(new VerifyUsage(mid), 30*1000);
}
private class VerifyUsage implements SimpleTimer.TimedEvent {
protected class VerifyUsage implements SimpleTimer.TimedEvent {
private Long _msgId;
public VerifyUsage(Long id) { _msgId = id; }
public void timeReached() {
MessagePayloadMessage removed = _availableMessages.remove(_msgId);
if (removed != null && !isClosed())
_log.log(Log.CRIT, "Message NOT removed! id=" + _msgId + ": " + removed);
_log.error("Message NOT removed! id=" + _msgId + ": " + removed);
}
}

View File

@ -93,7 +93,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
* set to false.
*/
private static final int DONT_COMPRESS_SIZE = 66;
private boolean shouldCompress(int size) {
protected boolean shouldCompress(int size) {
if (size <= DONT_COMPRESS_SIZE)
return false;
String p = getOptions().getProperty("i2cp.gzip");
@ -102,12 +102,35 @@ class I2PSessionImpl2 extends I2PSessionImpl {
return SHOULD_COMPRESS;
}
public void addSessionListener(I2PSessionListener lsnr, int proto, int port) {
throw new IllegalArgumentException("Use MuxedImpl");
}
public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port) {
throw new IllegalArgumentException("Use MuxedImpl");
}
public void removeListener(int proto, int port) {
throw new IllegalArgumentException("Use MuxedImpl");
}
public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException {
throw new IllegalArgumentException("Use MuxedImpl");
}
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
int proto, int fromport, int toport) throws I2PSessionException {
throw new IllegalArgumentException("Use MuxedImpl");
}
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expire,
int proto, int fromport, int toport) throws I2PSessionException {
throw new IllegalArgumentException("Use MuxedImpl");
}
@Override
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException {
return sendMessage(dest, payload, 0, payload.length);
}
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size) throws I2PSessionException {
return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64), 0);
// we don't do end-to-end crypto any more
//return sendMessage(dest, payload, offset, size, new SessionKey(), new HashSet(64), 0);
return sendMessage(dest, payload, offset, size, null, null, 0);
}
@Override
@ -173,7 +196,7 @@ class I2PSessionImpl2 extends I2PSessionImpl {
private static final int NUM_TAGS = 50;
private boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
protected boolean sendBestEffort(Destination dest, byte payload[], SessionKey keyUsed, Set tagsSent, long expires)
throws I2PSessionException {
SessionKey key = null;
SessionKey newKey = null;

View File

@ -20,7 +20,7 @@ public interface I2PSessionListener {
* size # of bytes.
* @param session session to notify
* @param msgId message number available
* @param size size of the message
* @param size size of the message - why it's a long and not an int is a mystery
*/
void messageAvailable(I2PSession session, int msgId, long size);
@ -42,4 +42,4 @@ public interface I2PSessionListener {
*
*/
void errorOccurred(I2PSession session, String message, Throwable error);
}
}

View File

@ -0,0 +1,320 @@
package net.i2p.client;
/*
* public domain
*/
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.SessionKey;
import net.i2p.data.SessionTag;
import net.i2p.data.i2cp.MessagePayloadMessage;
import net.i2p.util.Log;
import net.i2p.util.SimpleScheduler;
/**
* I2PSession with protocol and ports
*
* Streaming lib has been modified to send I2PSession.PROTO_STREAMING but
* still receives all. It sends with fromPort and toPort = 0, and receives on all ports.
*
* No datagram apps have been modified yet.
* Therefore the compatibility situation is as follows:
*
* Compatibility:
* old streaming -> new streaming: sends proto anything, rcvs proto anything
* new streaming -> old streaming: sends PROTO_STREAMING, ignores rcvd proto
* old datagram -> new datagram: sends proto anything, rcvs proto anything
* new datagram -> old datagram: sends PROTO_DATAGRAM, ignores rcvd proto
* In all the above cases, streaming and datagram receive traffic for the other
* protocol, same as before.
*
* old datagram -> new muxed: doesn't work because the old sends proto 0 but the udp side
* of the mux registers with PROTO_DATAGRAM, so the datagrams
* go to the streaming side, same as before.
* old streaming -> new muxed: works
*
* Typical Usage:
* Streaming + datagrams:
* I2PSocketManager sockMgr = getSocketManager();
* I2PSession session = sockMgr.getSession();
* session.addMuxedSessionListener(myI2PSessionMuxedListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
* * or *
* session.addSessionListener(myI2PSessionListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
* session.sendMessage(dest, payload, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
*
* Datagrams only, with multiple ports:
* I2PClient client = I2PClientFactory.createClient();
* ...
* I2PSession session = client.createSession(...);
* session.addMuxedSessionListener(myI2PSessionMuxedListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
* * or *
* session.addSessionListener(myI2PSessionListener, I2PSession.PROTO_DATAGRAM, I2PSession.PORT_ANY);
* session.sendMessage(dest, payload, I2PSession.PROTO_DATAGRAM, fromPort, toPort);
*
* Multiple streaming ports:
* Needs some streaming lib hacking
*
* @author zzz
*/
class I2PSessionMuxedImpl extends I2PSessionImpl2 implements I2PSession {
private I2PSessionDemultiplexer _demultiplexer;
public I2PSessionMuxedImpl(I2PAppContext ctx, InputStream destKeyStream, Properties options) throws I2PSessionException {
super(ctx, destKeyStream, options);
// also stored in _sessionListener but we keep it in _demultipexer
// as well so we don't have to keep casting
_demultiplexer = new I2PSessionDemultiplexer(ctx);
super.setSessionListener(_demultiplexer);
// discards the one in super(), sorry about that... (no it wasn't started yet)
_availabilityNotifier = new MuxedAvailabilityNotifier();
}
/** listen on all protocols and ports */
@Override
public void setSessionListener(I2PSessionListener lsnr) {
_demultiplexer.addListener(lsnr, PROTO_ANY, PORT_ANY);
}
/**
* Listen on specified protocol and port.
*
* An existing listener with the same proto and port is replaced.
* Only the listener with the best match is called back for each message.
*
* @param proto 1-254 or PROTO_ANY for all; recommended:
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param port 1-65535 or PORT_ANY for all
*/
public void addSessionListener(I2PSessionListener lsnr, int proto, int port) {
_demultiplexer.addListener(lsnr, proto, port);
}
/**
* Listen on specified protocol and port, and receive notification
* of proto, fromPort, and toPort for every message.
* @param proto 1-254 or 0 for all; 255 disallowed
* @param port 1-65535 or 0 for all
*/
public void addMuxedSessionListener(I2PSessionMuxedListener l, int proto, int port) {
_demultiplexer.addMuxedListener(l, proto, port);
}
/** removes the specified listener (only) */
public void removeListener(int proto, int port) {
_demultiplexer.removeListener(proto, port);
}
@Override
public boolean sendMessage(Destination dest, byte[] payload) throws I2PSessionException {
return sendMessage(dest, payload, 0, payload.length, null, null,
0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED);
}
@Override
public boolean sendMessage(Destination dest, byte[] payload, int proto, int fromport, int toport) throws I2PSessionException {
return sendMessage(dest, payload, 0, payload.length, null, null, 0, proto, fromport, toport);
}
@Override
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
SessionKey keyUsed, Set tagsSent, long expires)
throws I2PSessionException {
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, PROTO_UNSPECIFIED, PORT_UNSPECIFIED, PORT_UNSPECIFIED);
}
@Override
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent,
int proto, int fromport, int toport) throws I2PSessionException {
return sendMessage(dest, payload, offset, size, keyUsed, tagsSent, 0, proto, fromport, toport);
}
/**
* @param proto 1-254 or 0 for unset; recommended:
* I2PSession.PROTO_UNSPECIFIED
* I2PSession.PROTO_STREAMING
* I2PSession.PROTO_DATAGRAM
* 255 disallowed
* @param fromport 1-65535 or 0 for unset
* @param toport 1-65535 or 0 for unset
*/
public boolean sendMessage(Destination dest, byte[] payload, int offset, int size,
SessionKey keyUsed, Set tagsSent, long expires,
int proto, int fromPort, int toPort)
throws I2PSessionException {
if (isClosed()) throw new I2PSessionException("Already closed");
updateActivity();
boolean sc = shouldCompress(size);
if (sc)
payload = DataHelper.compress(payload, offset, size);
else
payload = DataHelper.compress(payload, offset, size, DataHelper.NO_COMPRESSION);
setProto(payload, proto);
setFromPort(payload, fromPort);
setToPort(payload, toPort);
_context.statManager().addRateData("i2cp.tx.msgCompressed", payload.length, 0);
_context.statManager().addRateData("i2cp.tx.msgExpanded", size, 0);
return sendBestEffort(dest, payload, keyUsed, tagsSent, expires);
}
/**
* Receive a payload message and let the app know its available
*/
@Override
public void addNewMessage(MessagePayloadMessage msg) {
Long mid = new Long(msg.getMessageId());
_availableMessages.put(mid, msg);
long id = msg.getMessageId();
byte data[] = msg.getPayload().getUnencryptedData();
if ((data == null) || (data.length <= 0)) {
if (_log.shouldLog(Log.CRIT))
_log.log(Log.CRIT, getPrefix() + "addNewMessage of a message with no unencrypted data",
new Exception("Empty message"));
return;
}
int size = data.length;
if (size < 10) {
_log.error(getPrefix() + "length too short for gzip header: " + size);
return;
}
((MuxedAvailabilityNotifier)_availabilityNotifier).available(id, size, getProto(msg),
getFromPort(msg), getToPort(msg));
SimpleScheduler.getInstance().addEvent(new VerifyUsage(mid), 30*1000);
}
protected class MuxedAvailabilityNotifier extends AvailabilityNotifier {
private LinkedBlockingQueue<MsgData> _msgs;
private boolean _alive;
private static final int POISON_SIZE = -99999;
public MuxedAvailabilityNotifier() {
_msgs = new LinkedBlockingQueue();
}
public void stopNotifying() {
_msgs.clear();
if (_alive) {
_alive = false;
try {
_msgs.put(new MsgData(0, POISON_SIZE, 0, 0, 0));
} catch (InterruptedException ie) {}
}
}
/** unused */
public void available(long msgId, int size) { throw new IllegalArgumentException("no"); }
public void available(long msgId, int size, int proto, int fromPort, int toPort) {
try {
_msgs.put(new MsgData((int)(msgId & 0xffffffff), size, proto, fromPort, toPort));
} catch (InterruptedException ie) {}
}
public void run() {
_alive = true;
while (true) {
MsgData msg;
try {
msg = _msgs.take();
} catch (InterruptedException ie) {
continue;
}
if (msg.size == POISON_SIZE)
break;
try {
_demultiplexer.messageAvailable(I2PSessionMuxedImpl.this, msg.id,
msg.size, msg.proto, msg.fromPort, msg.toPort);
} catch (Exception e) {
_log.error("Error notifying app of message availability");
}
}
}
}
/** let's keep this simple */
private static class MsgData {
public int id, size, proto, fromPort, toPort;
public MsgData(int i, int s, int p, int f, int t) {
id = i;
size = s;
proto = p;
fromPort = f;
toPort = t;
}
}
/**
* No, we couldn't put any protocol byte in front of everything and
* keep backward compatibility. But there are several bytes that
* are unused AND unchecked in the gzip header in releases <= 0.7.
* So let's use 5 of them for a protocol and two 2-byte ports.
*
* Following are all the methods to hide the
* protocol, fromPort, and toPort in the gzip header
*
* The fields used are all ignored on receive in ResettableGzipInputStream
*
* See also ResettableGzipOutputStream.
* Ref: RFC 1952
*
*/
/** OS byte in gzip header */
private static final int PROTO_BYTE = 9;
/** Upper two bytes of MTIME in gzip header */
private static final int FROMPORT_BYTES = 4;
/** Lower two bytes of MTIME in gzip header */
private static final int TOPORT_BYTES = 6;
/** Non-muxed sets the OS byte to 0xff */
private static int getProto(MessagePayloadMessage msg) {
int rv = getByte(msg, PROTO_BYTE) & 0xff;
return rv == 0xff ? PROTO_UNSPECIFIED : rv;
}
/** Non-muxed sets the MTIME bytes to 0 */
private static int getFromPort(MessagePayloadMessage msg) {
return (((getByte(msg, FROMPORT_BYTES) & 0xff) << 8) |
(getByte(msg, FROMPORT_BYTES + 1) & 0xff));
}
/** Non-muxed sets the MTIME bytes to 0 */
private static int getToPort(MessagePayloadMessage msg) {
return (((getByte(msg, TOPORT_BYTES) & 0xff) << 8) |
(getByte(msg, TOPORT_BYTES + 1) & 0xff));
}
private static int getByte(MessagePayloadMessage msg, int i) {
return msg.getPayload().getUnencryptedData()[i] & 0xff;
}
private static void setProto(byte[] payload, int p) {
payload[PROTO_BYTE] = (byte) (p & 0xff);
}
private static void setFromPort(byte[] payload, int p) {
payload[FROMPORT_BYTES] = (byte) ((p >> 8) & 0xff);
payload[FROMPORT_BYTES + 1] = (byte) (p & 0xff);
}
private static void setToPort(byte[] payload, int p) {
payload[TOPORT_BYTES] = (byte) ((p >> 8) & 0xff);
payload[TOPORT_BYTES + 1] = (byte) (p & 0xff);
}
}

View File

@ -0,0 +1,62 @@
package net.i2p.client;
/*
* public domain
*/
/**
* Define a means for the router to asynchronously notify the client that a
* new message is available or the router is under attack.
*
* @author zzz extends I2PSessionListener
*/
public interface I2PSessionMuxedListener extends I2PSessionListener {
/**
* Will be called only if you register via
* setSessionListener() or addSessionListener().
* And if you are doing that, just use I2PSessionListener.
*
* If you register via addSessionListener(),
* this will be called only for the proto(s) and toport(s) you register for.
*
* @param session session to notify
* @param msgId message number available
* @param size size of the message - why it's a long and not an int is a mystery
*/
void messageAvailable(I2PSession session, int msgId, long size);
/**
* Instruct the client that the given session has received a message
*
* Will be called only if you register via addMuxedSessionListener().
* Will be called only for the proto(s) and toport(s) you register for.
*
* @param session session to notify
* @param msgId message number available
* @param size size of the message - why it's a long and not an int is a mystery
* @param proto 1-254 or 0 for unspecified
* @param fromport 1-65535 or 0 for unspecified
* @param toport 1-65535 or 0 for unspecified
*/
void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport);
/** Instruct the client that the session specified seems to be under attack
* and that the client may wish to move its destination to another router.
* @param session session to report abuse to
* @param severity how bad the abuse is
*/
void reportAbuse(I2PSession session, int severity);
/**
* Notify the client that the session has been terminated
*
*/
void disconnected(I2PSession session);
/**
* Notify the client that some error occurred
*
*/
void errorOccurred(I2PSession session, String message, Throwable error);
}

View File

@ -16,8 +16,10 @@ import java.util.Set;
import java.util.StringTokenizer;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
@ -135,4 +137,34 @@ public class HostsTxtNamingService extends NamingService {
}
return null;
}
@Override
public String reverseLookup(Hash h) {
List filenames = getFilenames();
for (int i = 0; i < filenames.size(); i++) {
String hostsfile = (String)filenames.get(i);
Properties hosts = new Properties();
try {
File f = new File(hostsfile);
if ( (f.exists()) && (f.canRead()) ) {
DataHelper.loadProps(hosts, f, true);
Set keyset = hosts.keySet();
Iterator iter = keyset.iterator();
while (iter.hasNext()) {
String host = (String)iter.next();
String key = hosts.getProperty(host);
try {
Destination destkey = new Destination();
destkey.fromBase64(key);
if (h.equals(destkey.calculateHash()))
return host;
} catch (DataFormatException dfe) {}
}
}
} catch (Exception ioe) {
_log.error("Error loading hosts file " + hostsfile, ioe);
}
}
return null;
}
}

View File

@ -16,6 +16,7 @@ import java.util.Map;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
@ -61,6 +62,7 @@ public abstract class NamingService {
* <code>null</code> if no reverse lookup is possible.
*/
public abstract String reverseLookup(Destination dest);
public String reverseLookup(Hash h) { return null; };
/**
* Check if host name is valid Base64 encoded dest and return this

View File

@ -1,5 +1,6 @@
package net.i2p.stat;
import java.text.Collator;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -178,7 +179,7 @@ public class StatManager {
/** Group name (String) to a Set of stat names, ordered alphabetically */
public Map getStatsByGroup() {
Map groups = new TreeMap();
Map groups = new TreeMap(Collator.getInstance());
for (Iterator iter = _frequencyStats.values().iterator(); iter.hasNext();) {
FrequencyStat stat = (FrequencyStat) iter.next();
if (!groups.containsKey(stat.getGroupName())) groups.put(stat.getGroupName(), new TreeSet());

View File

@ -0,0 +1,76 @@
package net.i2p.util;
import net.i2p.I2PAppContext;
import net.i2p.data.Base32;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
/**
* Convert any kind of destination String to a hash
* Supported:
* Base64 dest
* Base64 dest.i2p
* Base64 Hash
* Base32 Hash
* Base32 desthash.b32.i2p
* example.i2p
*
* @return null on failure
*
* @author zzz
*/
public class ConvertToHash {
public static Hash getHash(String peer) {
if (peer == null)
return null;
Hash h = new Hash();
String peerLC = peer.toLowerCase();
// b64 hash
if (peer.length() == 44 && !peerLC.endsWith(".i2p")) {
try {
h.fromBase64(peer);
} catch (DataFormatException dfe) {}
}
// b64 dest.i2p
if (h.getData() == null && peer.length() >= 520 && peerLC.endsWith(".i2p")) {
try {
Destination d = new Destination();
d.fromBase64(peer.substring(0, peer.length() - 4));
h = d.calculateHash();
} catch (DataFormatException dfe) {}
}
// b64 dest
if (h.getData() == null && peer.length() >= 516 && !peerLC.endsWith(".i2p")) {
try {
Destination d = new Destination();
d.fromBase64(peer);
h = d.calculateHash();
} catch (DataFormatException dfe) {}
}
// b32 hash.b32.i2p
// do this here rather than in naming service so it will work
// even if the leaseset is not found
if (h.getData() == null && peer.length() == 60 && peerLC.endsWith(".b32.i2p")) {
byte[] b = Base32.decode(peer.substring(0, 52));
if (b != null && b.length == Hash.HASH_LENGTH)
h.setData(b);
}
// b32 hash
if (h.getData() == null && peer.length() == 52 && !peerLC.endsWith(".i2p")) {
byte[] b = Base32.decode(peer);
if (b != null && b.length == Hash.HASH_LENGTH)
h.setData(b);
}
// example.i2p
if (h.getData() == null) {
Destination d = I2PAppContext.getGlobalContext().namingService().lookup(peer);
if (d != null)
h = d.calculateHash();
}
if (h.getData() == null)
return null;
return h;
}
}

View File

@ -23,6 +23,9 @@ import freenet.support.CPUInformation.CPUInfo;
import freenet.support.CPUInformation.IntelCPUInfo;
import freenet.support.CPUInformation.UnknownCPUException;
import net.i2p.I2PAppContext;
import net.i2p.util.Log;
/**
* <p>BigInteger that takes advantage of the jbigi library for the modPow operation,
* which accounts for a massive segment of the processing cost of asymmetric
@ -89,6 +92,9 @@ public class NativeBigInteger extends BigInteger {
* do we want to dump some basic success/failure info to stderr during
* initialization? this would otherwise use the Log component, but this makes
* it easier for other systems to reuse this class
*
* Well, we really want to use Log so if you are one of those "other systems"
* then comment out the I2PAppContext usage below.
*/
private static final boolean _doLog = System.getProperty("jbigi.dontLog") == null;
@ -401,38 +407,32 @@ public class NativeBigInteger extends BigInteger {
boolean loaded = loadGeneric("jbigi");
if (loaded) {
_nativeOk = true;
if (_doLog)
System.err.println("INFO: Locally optimized native BigInteger loaded from the library path");
info("Locally optimized native BigInteger library loaded from the library path");
} else {
loaded = loadFromResource("jbigi");
if (loaded) {
_nativeOk = true;
if (_doLog)
System.err.println("INFO: Locally optimized native BigInteger loaded from resource");
info("Locally optimized native BigInteger library loaded from resource");
} else {
loaded = loadFromResource(true);
if (loaded) {
_nativeOk = true;
if (_doLog)
System.err.println("INFO: Optimized native BigInteger library '"+getResourceName(true)+"' loaded from resource");
info("Optimized native BigInteger library '"+getResourceName(true)+"' loaded from resource");
} else {
loaded = loadGeneric(true);
if (loaded) {
_nativeOk = true;
if (_doLog)
System.err.println("INFO: Optimized native BigInteger library '"+getMiddleName(true)+"' loaded from somewhere in the path");
info("Optimized native BigInteger library '"+getMiddleName(true)+"' loaded from somewhere in the path");
} else {
loaded = loadFromResource(false);
if (loaded) {
_nativeOk = true;
if (_doLog)
System.err.println("INFO: Non-optimized native BigInteger library '"+getResourceName(false)+"' loaded from resource");
info("Non-optimized native BigInteger library '"+getResourceName(false)+"' loaded from resource");
} else {
loaded = loadGeneric(false);
if (loaded) {
_nativeOk = true;
if (_doLog)
System.err.println("INFO: Non-optimized native BigInteger library '"+getMiddleName(false)+"' loaded from somewhere in the path");
info("Non-optimized native BigInteger library '"+getMiddleName(false)+"' loaded from somewhere in the path");
} else {
_nativeOk = false;
}
@ -442,16 +442,27 @@ public class NativeBigInteger extends BigInteger {
}
}
}
if (_doLog && !_nativeOk)
System.err.println("INFO: Native BigInteger library jbigi not loaded - using pure java");
if (!_nativeOk) {
warn("Native BigInteger library jbigi not loaded - using pure Java - " +
"poor performance may result - see http://www.i2p2.i2p/jbigi.html for help");
}
}catch(Exception e){
if (_doLog) {
System.err.println("INFO: Native BigInteger library jbigi not loaded, reason: '"+e.getMessage()+"' - using pure java");
e.printStackTrace();
}
warn("Native BigInteger library jbigi not loaded, reason: '"+e.getMessage()+"' - using pure java");
}
}
private static void info(String s) {
if(_doLog)
System.err.println("INFO: " + s);
I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).info(s);
}
private static void warn(String s) {
if(_doLog)
System.err.println("WARNING: " + s);
I2PAppContext.getGlobalContext().logManager().getLog(NativeBigInteger.class).warn(s);
}
/**
* <p>Try loading it from an explictly build jbigi.dll / libjbigi.so first, before
* looking into a jbigi.jar for any other libraries.</p>