forked from I2P_Developers/i2p.i2p
propagate from branch 'i2p.i2p' (head 1de143fff53bb56e6eac926d6293d62200f0c392)
to branch 'i2p.i2p.zzz.multisess' (head 70fc07857232668b93ca6ba02c433dffc7639132)
This commit is contained in:
@ -9,6 +9,8 @@ package net.i2p.client;
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
@ -21,7 +23,7 @@ import net.i2p.data.SigningPrivateKey;
|
||||
/**
|
||||
* <p>Define the standard means of sending and receiving messages on the
|
||||
* I2P network by using the I2CP (the client protocol). This is done over a
|
||||
* bidirectional TCP socket and never sends any private keys.
|
||||
* bidirectional TCP socket.
|
||||
*
|
||||
* End to end encryption in I2PSession was disabled in release 0.6.
|
||||
*
|
||||
@ -247,6 +249,27 @@ public interface I2PSession {
|
||||
*
|
||||
*/
|
||||
public void destroySession() throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* @return a new subsession, non-null
|
||||
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
||||
* and different signing keys
|
||||
* @param opts subsession options if any, may be null
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public I2PSession addSubsession(InputStream privateKeyStream, Properties opts) throws I2PSessionException;
|
||||
|
||||
/**
|
||||
* @return a list of subsessions, non-null, does not include the primary session
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public void removeSubsession(I2PSession session);
|
||||
|
||||
/**
|
||||
* @return a list of subsessions, non-null, does not include the primary session
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public List<I2PSession> getSubsessions();
|
||||
|
||||
/**
|
||||
* Actually connect the session and start receiving/sending messages
|
||||
|
@ -74,7 +74,9 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
|
||||
* (Streaming lib)
|
||||
*/
|
||||
public void addListener(I2PSessionListener l, int proto, int port) {
|
||||
_listeners.put(key(proto, port), new NoPortsListener(l));
|
||||
I2PSessionListener old = _listeners.put(key(proto, port), new NoPortsListener(l));
|
||||
if (old != null && _log.shouldLog(Log.WARN))
|
||||
_log.warn("Listener " + l + " replaces " + old + " for proto: " + proto + " port: " + port);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +84,9 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
|
||||
* UDP perhaps
|
||||
*/
|
||||
public void addMuxedListener(I2PSessionMuxedListener l, int proto, int port) {
|
||||
_listeners.put(key(proto, port), l);
|
||||
I2PSessionListener old = _listeners.put(key(proto, port), l);
|
||||
if (old != null && _log.shouldLog(Log.WARN))
|
||||
_log.warn("Listener " + l + " replaces " + old + " for proto: " + proto + " port: " + port);
|
||||
}
|
||||
|
||||
public void removeListener(int proto, int port) {
|
||||
|
@ -23,6 +23,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -43,6 +44,7 @@ import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessageReader;
|
||||
import net.i2p.data.i2cp.MessagePayloadMessage;
|
||||
import net.i2p.data.i2cp.SessionId;
|
||||
import net.i2p.data.i2cp.SessionStatusMessage;
|
||||
import net.i2p.internal.I2CPMessageQueue;
|
||||
import net.i2p.internal.InternalClientManager;
|
||||
import net.i2p.internal.QueuedI2CPMessageReader;
|
||||
@ -81,6 +83,15 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
/** currently granted lease set, or null */
|
||||
private volatile LeaseSet _leaseSet;
|
||||
|
||||
// subsession stuff
|
||||
// registered subsessions
|
||||
private final List<SubSession> _subsessions;
|
||||
// established subsessions
|
||||
private final ConcurrentHashMap<SessionId, SubSession> _subsessionMap;
|
||||
private final Object _subsessionLock = new Object();
|
||||
private static final String MIN_SUBSESSION_VERSION = "0.9.19";
|
||||
private volatile boolean _routerSupportsSubsessions;
|
||||
|
||||
/** hostname of router - will be null if in RouterContext */
|
||||
protected final String _hostname;
|
||||
/** port num to router - will be 0 if in RouterContext */
|
||||
@ -186,6 +197,9 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
TEST_LOOKUP ||
|
||||
(routerVersion != null && routerVersion.length() > 0 &&
|
||||
VersionComparator.comp(routerVersion, MIN_HOST_LOOKUP_VERSION) >= 0);
|
||||
_routerSupportsSubsessions = _context.isRouterContext() ||
|
||||
(routerVersion != null && routerVersion.length() > 0 &&
|
||||
VersionComparator.comp(routerVersion, MIN_SUBSESSION_VERSION) >= 0);
|
||||
synchronized (_stateLock) {
|
||||
if (_state == State.OPENING) {
|
||||
_state = State.GOTDATE;
|
||||
@ -203,18 +217,42 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
*/
|
||||
protected I2PSessionImpl(I2PAppContext context, Properties options,
|
||||
I2PClientMessageHandlerMap handlerMap) {
|
||||
this(context, options, handlerMap, false);
|
||||
this(context, options, handlerMap, null, false);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For extension by SubSession via I2PSessionMuxedImpl and I2PSessionImpl2
|
||||
*
|
||||
* @param destKeyStream stream containing the private key data,
|
||||
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
|
||||
* @param options set of options to configure the router with, if null will use System properties
|
||||
* @since 0.9.19
|
||||
*/
|
||||
protected I2PSessionImpl(I2PSessionImpl primary, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
this(primary.getContext(), options, primary.getHandlerMap(), primary.getProducer(), true);
|
||||
_availabilityNotifier = new AvailabilityNotifier();
|
||||
try {
|
||||
readDestination(destKeyStream);
|
||||
} catch (DataFormatException dfe) {
|
||||
throw new I2PSessionException("Error reading the destination key stream", dfe);
|
||||
} catch (IOException ioe) {
|
||||
throw new I2PSessionException("Error reading the destination key stream", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic setup of finals
|
||||
* @since 0.9.7
|
||||
*/
|
||||
private I2PSessionImpl(I2PAppContext context, Properties options,
|
||||
I2PClientMessageHandlerMap handlerMap, boolean hasDest) {
|
||||
I2PClientMessageHandlerMap handlerMap,
|
||||
I2CPMessageProducer producer,
|
||||
boolean hasDest) {
|
||||
_context = context;
|
||||
_handlerMap = handlerMap;
|
||||
_log = context.logManager().getLog(getClass());
|
||||
_subsessions = new CopyOnWriteArrayList<SubSession>();
|
||||
_subsessionMap = new ConcurrentHashMap<SessionId, SubSession>(4);
|
||||
if (options == null)
|
||||
options = (Properties) System.getProperties().clone();
|
||||
_options = loadConfig(options);
|
||||
@ -222,7 +260,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
_portNum = getPort();
|
||||
_fastReceive = Boolean.parseBoolean(_options.getProperty(I2PClient.PROP_FAST_RECEIVE));
|
||||
if (hasDest) {
|
||||
_producer = new I2CPMessageProducer(context);
|
||||
_producer = producer;
|
||||
_availableMessages = new ConcurrentHashMap<Long, MessagePayloadMessage>();
|
||||
_myDestination = new Destination();
|
||||
_privateKey = new PrivateKey();
|
||||
@ -236,6 +274,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
}
|
||||
_routerSupportsFastReceive = _context.isRouterContext();
|
||||
_routerSupportsHostLookup = _context.isRouterContext();
|
||||
_routerSupportsSubsessions = _context.isRouterContext();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -247,10 +286,10 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
* @param destKeyStream stream containing the private key data,
|
||||
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
|
||||
* @param options set of options to configure the router with, if null will use System properties
|
||||
* @throws I2PSessionException if there is a problem loading the private keys or
|
||||
* @throws I2PSessionException if there is a problem loading the private keys
|
||||
*/
|
||||
public I2PSessionImpl(I2PAppContext context, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
this(context, options, new I2PClientMessageHandlerMap(context), true);
|
||||
this(context, options, new I2PClientMessageHandlerMap(context), new I2CPMessageProducer(context), true);
|
||||
_availabilityNotifier = new AvailabilityNotifier();
|
||||
try {
|
||||
readDestination(destKeyStream);
|
||||
@ -260,6 +299,69 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
throw new I2PSessionException("Error reading the destination key stream", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Router must be connected or was connected... for now.
|
||||
*
|
||||
* @return a new subsession, non-null
|
||||
* @param privateKeyStream null for transient, if non-null must have same encryption keys as primary session
|
||||
* and different signing keys
|
||||
* @param opts subsession options if any, may be null
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public I2PSession addSubsession(InputStream privateKeyStream, Properties opts) throws I2PSessionException {
|
||||
if (!_routerSupportsSubsessions)
|
||||
throw new I2PSessionException("Router does not support subsessions");
|
||||
SubSession sub;
|
||||
synchronized(_subsessionLock) {
|
||||
if (_subsessions.size() > _subsessionMap.size())
|
||||
throw new I2PSessionException("Subsession request already pending");
|
||||
sub = new SubSession(this, privateKeyStream, opts);
|
||||
for (SubSession ss : _subsessions) {
|
||||
if (ss.getDecryptionKey().equals(sub.getDecryptionKey()) &&
|
||||
ss.getPrivateKey().equals(sub.getPrivateKey())) {
|
||||
throw new I2PSessionException("Dup subsession");
|
||||
}
|
||||
}
|
||||
_subsessions.add(sub);
|
||||
}
|
||||
|
||||
synchronized (_stateLock) {
|
||||
if (_state == State.OPEN) {
|
||||
_producer.connect(sub);
|
||||
} // else will be called in connect()
|
||||
}
|
||||
return sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public void removeSubsession(I2PSession session) {
|
||||
if (!(session instanceof SubSession))
|
||||
return;
|
||||
synchronized(_subsessionLock) {
|
||||
_subsessions.remove(session);
|
||||
SessionId id = ((SubSession) session).getSessionId();
|
||||
if (id != null)
|
||||
_subsessionMap.remove(id);
|
||||
/// tell the subsession
|
||||
try {
|
||||
// doesn't really throw
|
||||
session.destroySession();
|
||||
} catch (I2PSessionException ise) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of subsessions, non-null, does not include the primary session
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public List<I2PSession> getSubsessions() {
|
||||
synchronized(_subsessionLock) {
|
||||
return new ArrayList<I2PSession>(_subsessions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the config for anything we know about.
|
||||
@ -553,6 +655,16 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
startIdleMonitor();
|
||||
startVerifyUsage();
|
||||
success = true;
|
||||
|
||||
// now send CreateSessionMessages for all subsessions, one at a time, must wait for each response
|
||||
synchronized(_subsessionLock) {
|
||||
for (SubSession ss : _subsessions) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix() + "Connecting subsession " + ss);
|
||||
_producer.connect(ss);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InterruptedException ie) {
|
||||
throw new I2PSessionException("Interrupted", ie);
|
||||
} catch (UnknownHostException uhe) {
|
||||
@ -763,19 +875,80 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
/**
|
||||
* The I2CPMessageEventListener callback.
|
||||
* Recieve notification of some I2CP message and handle it if possible.
|
||||
*
|
||||
* We route the message based on message type AND session ID.
|
||||
*
|
||||
* The following types never contain a session ID and are not routable to
|
||||
* a subsession:
|
||||
* BandwidthLimitsMessage, DestReplyMessage
|
||||
*
|
||||
* The following types may not ontain a valid session ID
|
||||
* even when intended for a subsession, so we must take special care:
|
||||
* SessionStatusMessage
|
||||
*
|
||||
* @param reader unused
|
||||
*/
|
||||
public void messageReceived(I2CPMessageReader reader, I2CPMessage message) {
|
||||
I2CPMessageHandler handler = _handlerMap.getHandler(message.getType());
|
||||
if (handler == null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "Unknown message or unhandleable message received: type = "
|
||||
+ message.getType());
|
||||
int type = message.getType();
|
||||
SessionId id = message.sessionId();
|
||||
if (id == null || id.equals(_sessionId) ||
|
||||
(_sessionId == null && id != null && type == SessionStatusMessage.MESSAGE_TYPE)) {
|
||||
// it's for us
|
||||
I2CPMessageHandler handler = _handlerMap.getHandler(type);
|
||||
if (handler != null) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Message received of type " + type
|
||||
+ " to be handled by " + handler.getClass().getSimpleName());
|
||||
handler.handleMessage(message, this);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "Unknown message or unhandleable message received: type = "
|
||||
+ type);
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Message received of type " + message.getType()
|
||||
+ " to be handled by " + handler.getClass().getSimpleName());
|
||||
handler.handleMessage(message, this);
|
||||
SubSession sub = _subsessionMap.get(id);
|
||||
if (sub != null) {
|
||||
// it's for a subsession
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "Message received of type " + type
|
||||
+ " to be handled by " + sub);
|
||||
sub.messageReceived(reader, message);
|
||||
} else if (id != null && type == SessionStatusMessage.MESSAGE_TYPE) {
|
||||
// look for a subsession without a session
|
||||
synchronized (_subsessionLock) {
|
||||
for (SubSession sess : _subsessions) {
|
||||
if (sess.getSessionId() == null) {
|
||||
sess.messageReceived(reader, message);
|
||||
id = sess.getSessionId();
|
||||
if (id != null) {
|
||||
if (id.equals(_sessionId)) {
|
||||
// shouldnt happen
|
||||
sess.setSessionId(null);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dup or our session id " + id);
|
||||
} else {
|
||||
SubSession old = _subsessionMap.putIfAbsent(id, sess);
|
||||
if (old != null) {
|
||||
// shouldnt happen
|
||||
sess.setSessionId(null);
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Dup session id " + id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "No session " + id + " to handle message: type = "
|
||||
+ type);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// it's for nobody
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "No session " + id + " to handle message: type = "
|
||||
+ type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -810,6 +983,18 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
*/
|
||||
I2CPMessageProducer getProducer() { return _producer; }
|
||||
|
||||
/**
|
||||
* For Subsessions
|
||||
* @since 0.9.19
|
||||
*/
|
||||
I2PClientMessageHandlerMap getHandlerMap() { return _handlerMap; }
|
||||
|
||||
/**
|
||||
* For Subsessions
|
||||
* @since 0.9.19
|
||||
*/
|
||||
I2PAppContext getContext() { return _context; }
|
||||
|
||||
/**
|
||||
* Retrieve the configuration options, filtered.
|
||||
* All defaults passed in via constructor have been promoted to the primary map.
|
||||
@ -923,6 +1108,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
|
||||
if (_availabilityNotifier != null)
|
||||
_availabilityNotifier.stopNotifying();
|
||||
closeSocket();
|
||||
_subsessionMap.clear();
|
||||
if (_sessionListener != null) _sessionListener.disconnected(this);
|
||||
}
|
||||
|
||||
|
@ -50,9 +50,9 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
|
||||
private static final long REMOVE_EXPIRED_TIME = 63*1000;
|
||||
|
||||
/**
|
||||
* for extension by SimpleSession (no dest)
|
||||
*/
|
||||
/**
|
||||
* for extension by SimpleSession (no dest)
|
||||
*/
|
||||
protected I2PSessionImpl2(I2PAppContext context, Properties options,
|
||||
I2PClientMessageHandlerMap handlerMap) {
|
||||
super(context, options, handlerMap);
|
||||
@ -61,15 +61,17 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* for extension by I2PSessionMuxedImpl
|
||||
*
|
||||
* Create a new session, reading the Destination, PrivateKey, and SigningPrivateKey
|
||||
* from the destKeyStream, and using the specified options to connect to the router
|
||||
*
|
||||
* @param destKeyStream stream containing the private key data,
|
||||
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
|
||||
* @param options set of options to configure the router with, if null will use System properties
|
||||
* @throws I2PSessionException if there is a problem loading the private keys or
|
||||
* @throws I2PSessionException if there is a problem loading the private keys
|
||||
*/
|
||||
public I2PSessionImpl2(I2PAppContext ctx, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
protected I2PSessionImpl2(I2PAppContext ctx, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
super(ctx, destKeyStream, options);
|
||||
_sendingStates = new ConcurrentHashMap<Long, MessageState>(32);
|
||||
_sendMessageNonce = new AtomicLong();
|
||||
@ -94,6 +96,26 @@ class I2PSessionImpl2 extends I2PSessionImpl {
|
||||
_context.statManager().createRateStat("i2cp.tx.msgExpanded", "size before compression", "i2cp", new long[] { 30*60*1000 });
|
||||
}
|
||||
|
||||
/*
|
||||
* For extension by SubSession via I2PSessionMuxedImpl
|
||||
*
|
||||
* @param destKeyStream stream containing the private key data,
|
||||
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
|
||||
* @param options set of options to configure the router with, if null will use System properties
|
||||
* @since 0.9.19
|
||||
*/
|
||||
protected I2PSessionImpl2(I2PSessionImpl primary, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
super(primary, destKeyStream, options);
|
||||
_sendingStates = new ConcurrentHashMap<Long, MessageState>(32);
|
||||
_sendMessageNonce = new AtomicLong();
|
||||
_noEffort = "none".equals(getOptions().getProperty(I2PClient.PROP_RELIABILITY, "").toLowerCase(Locale.US));
|
||||
_context.statManager().createRateStat("i2cp.receiveStatusTime.1", "How long it took to get status=1 back", "i2cp", new long[] { 10*60*1000 });
|
||||
_context.statManager().createRateStat("i2cp.receiveStatusTime.4", "How long it took to get status=4 back", "i2cp", new long[] { 10*60*1000 });
|
||||
_context.statManager().createRateStat("i2cp.receiveStatusTime.5", "How long it took to get status=5 back", "i2cp", new long[] { 10*60*1000 });
|
||||
_context.statManager().createRateStat("i2cp.tx.msgCompressed", "compressed size transferred", "i2cp", new long[] { 30*60*1000 });
|
||||
_context.statManager().createRateStat("i2cp.tx.msgExpanded", "size before compression", "i2cp", new long[] { 30*60*1000 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire up a periodic task to check for unclaimed messages
|
||||
* @since 0.9.14
|
||||
|
@ -82,6 +82,24 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
// discards the one in super(), sorry about that... (no it wasn't started yet)
|
||||
_availabilityNotifier = new MuxedAvailabilityNotifier();
|
||||
}
|
||||
|
||||
/*
|
||||
* For extension by SubSession
|
||||
*
|
||||
* @param destKeyStream stream containing the private key data,
|
||||
* format is specified in {@link net.i2p.data.PrivateKeyFile PrivateKeyFile}
|
||||
* @param options set of options to configure the router with, if null will use System properties
|
||||
* @since 0.9.19
|
||||
*/
|
||||
protected I2PSessionMuxedImpl(I2PSessionImpl primary, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
super(primary, 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(primary.getContext());
|
||||
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
|
||||
@ -315,9 +333,9 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
|
||||
protected class MuxedAvailabilityNotifier extends AvailabilityNotifier {
|
||||
private final LinkedBlockingQueue<MsgData> _msgs;
|
||||
private volatile boolean _alive = false;
|
||||
private volatile boolean _alive;
|
||||
private static final int POISON_SIZE = -99999;
|
||||
private final AtomicBoolean stopping = new AtomicBoolean(false);
|
||||
private final AtomicBoolean stopping = new AtomicBoolean();
|
||||
|
||||
public MuxedAvailabilityNotifier() {
|
||||
_msgs = new LinkedBlockingQueue<MsgData>();
|
||||
@ -325,12 +343,12 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
|
||||
@Override
|
||||
public void stopNotifying() {
|
||||
boolean again = true;
|
||||
synchronized (stopping) {
|
||||
if( !stopping.getAndSet(true)) {
|
||||
if (_alive == true) {
|
||||
_msgs.clear();
|
||||
if (_alive) {
|
||||
// System.out.println("I2PSessionMuxedImpl.stopNotifying()");
|
||||
_msgs.clear();
|
||||
boolean again = true;
|
||||
while(again) {
|
||||
try {
|
||||
_msgs.put(new MsgData(0, POISON_SIZE, 0, 0, 0));
|
||||
@ -340,8 +358,8 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_alive = false;
|
||||
}
|
||||
_alive = false;
|
||||
stopping.set(false);
|
||||
}
|
||||
// stopping.notifyAll();
|
||||
@ -355,17 +373,24 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 {
|
||||
try {
|
||||
_msgs.put(new MsgData((int)(msgId & 0xffffffff), size, proto, fromPort, toPort));
|
||||
} catch (InterruptedException ie) {}
|
||||
if (!_alive && _log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix() + "message available but notifier not running");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
MsgData msg;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix() + "starting muxed availability notifier");
|
||||
_msgs.clear();
|
||||
_alive=true;
|
||||
while (_alive) {
|
||||
MsgData msg;
|
||||
try {
|
||||
msg = _msgs.take();
|
||||
} catch (InterruptedException ie) {
|
||||
_log.debug("I2PSessionMuxedImpl.run() InterruptedException " + String.valueOf(_msgs.size()) + " Messages, Alive " + _alive);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("I2PSessionMuxedImpl.run() InterruptedException " +
|
||||
String.valueOf(_msgs.size()) + " Messages, Alive " + _alive);
|
||||
continue;
|
||||
}
|
||||
if (msg.size == POISON_SIZE) {
|
||||
|
@ -33,7 +33,7 @@ class MessagePayloadMessageHandler extends HandlerImpl {
|
||||
|
||||
public void handleMessage(I2CPMessage message, I2PSessionImpl session) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Handle message " + message);
|
||||
_log.debug("Handle message " + message + " for session " + session);
|
||||
try {
|
||||
MessagePayloadMessage msg = (MessagePayloadMessage) message;
|
||||
long id = msg.getMessageId();
|
||||
|
@ -88,9 +88,8 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
String sspk = session.getOptions().getProperty("i2cp.leaseSetSigningPrivateKey");
|
||||
PrivateKey privKey = null;
|
||||
SigningPrivateKey signingPrivKey = null;
|
||||
boolean useOldKeys;
|
||||
if (spk != null && sspk != null) {
|
||||
useOldKeys = true;
|
||||
boolean useOldKeys = true;
|
||||
int colon = sspk.indexOf(':');
|
||||
SigType type = dest.getSigType();
|
||||
if (colon > 0) {
|
||||
@ -111,6 +110,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
signingPrivKey.fromBase64(sspk);
|
||||
} catch (DataFormatException iae) {
|
||||
useOldKeys = false;
|
||||
signingPrivKey = null;
|
||||
}
|
||||
}
|
||||
if (useOldKeys) {
|
||||
@ -118,20 +118,36 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
privKey = new PrivateKey();
|
||||
privKey.fromBase64(spk);
|
||||
} catch (DataFormatException iae) {
|
||||
useOldKeys = false;
|
||||
privKey = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
useOldKeys = false;
|
||||
}
|
||||
if (useOldKeys)
|
||||
li = new LeaseInfo(privKey, signingPrivKey);
|
||||
else
|
||||
if (privKey == null && !_existingLeaseSets.isEmpty()) {
|
||||
// look for keypair from another dest using same pubkey
|
||||
PublicKey pk = dest.getPublicKey();
|
||||
for (Map.Entry<Destination, LeaseInfo> e : _existingLeaseSets.entrySet()) {
|
||||
if (pk.equals(e.getKey().getPublicKey())) {
|
||||
privKey = e.getValue().getPrivateKey();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating new leaseInfo keys for " + dest + " with private key from " + e.getKey());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (privKey != null) {
|
||||
if (signingPrivKey != null) {
|
||||
li = new LeaseInfo(privKey, signingPrivKey);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating new leaseInfo keys for " + dest + " WITH configured private keys");
|
||||
} else {
|
||||
li = new LeaseInfo(privKey, dest);
|
||||
}
|
||||
} else {
|
||||
li = new LeaseInfo(dest);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating new leaseInfo keys for " + dest + " without configured private keys");
|
||||
}
|
||||
_existingLeaseSets.put(dest, li);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Creating new leaseInfo keys for "
|
||||
+ dest + " using configured private keys? " + useOldKeys);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Caching the old leaseInfo keys for "
|
||||
@ -178,6 +194,9 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
private final SigningPublicKey _signingPubKey;
|
||||
private final SigningPrivateKey _signingPrivKey;
|
||||
|
||||
/**
|
||||
* New keys
|
||||
*/
|
||||
public LeaseInfo(Destination dest) {
|
||||
SimpleDataStructure encKeys[] = KeyGenerator.getInstance().generatePKIKeys();
|
||||
// must be same type as the Destination's signing key
|
||||
@ -194,6 +213,7 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Existing keys
|
||||
* @since 0.9.18
|
||||
*/
|
||||
public LeaseInfo(PrivateKey privKey, SigningPrivateKey signingPrivKey) {
|
||||
@ -203,6 +223,23 @@ class RequestLeaseSetMessageHandler extends HandlerImpl {
|
||||
_signingPrivKey = signingPrivKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Existing crypto key, new signing key
|
||||
* @since 0.9.20
|
||||
*/
|
||||
public LeaseInfo(PrivateKey privKey, Destination dest) {
|
||||
SimpleDataStructure signKeys[];
|
||||
try {
|
||||
signKeys = KeyGenerator.getInstance().generateSigningKeys(dest.getSigningPublicKey().getType());
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new IllegalStateException(gse);
|
||||
}
|
||||
_pubKey = KeyGenerator.getPublicKey(privKey);
|
||||
_privKey = privKey;
|
||||
_signingPubKey = (SigningPublicKey) signKeys[0];
|
||||
_signingPrivKey = (SigningPrivateKey) signKeys[1];
|
||||
}
|
||||
|
||||
public PublicKey getPublicKey() {
|
||||
return _pubKey;
|
||||
}
|
||||
|
321
core/java/src/net/i2p/client/SubSession.java
Normal file
321
core/java/src/net/i2p/client/SubSession.java
Normal file
@ -0,0 +1,321 @@
|
||||
package net.i2p.client;
|
||||
|
||||
/*
|
||||
* 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.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.PrivateKey;
|
||||
import net.i2p.data.SigningPrivateKey;
|
||||
import net.i2p.data.i2cp.CreateLeaseSetMessage;
|
||||
import net.i2p.data.i2cp.CreateSessionMessage;
|
||||
import net.i2p.data.i2cp.I2CPMessage;
|
||||
import net.i2p.data.i2cp.SessionId;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
* An additional session using another session's connection.
|
||||
*
|
||||
* A subsession uses the same connection to the router as the primary session,
|
||||
* but has a different Destination. It uses the same tunnels as the primary
|
||||
* but has its own leaseset. It must use the same encryption keys as the primary
|
||||
* so that garlic encryption/decryption works.
|
||||
*
|
||||
* The message handler map and message producer are reused from primary.
|
||||
*
|
||||
* Does NOT reuse the session listener ????
|
||||
*
|
||||
* While the I2CP protocol, in theory, allows for fully independent sessions
|
||||
* over the same I2CP connection, this is not currently supported by the router.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
class SubSession extends I2PSessionMuxedImpl {
|
||||
private final I2PSessionMuxedImpl _primary;
|
||||
|
||||
/**
|
||||
* @param primary must be a I2PSessionMuxedImpl
|
||||
*/
|
||||
public SubSession(I2PSession primary, InputStream destKeyStream, Properties options) throws I2PSessionException {
|
||||
super((I2PSessionMuxedImpl)primary, destKeyStream, options);
|
||||
_primary = (I2PSessionMuxedImpl) primary;
|
||||
if (!getDecryptionKey().equals(_primary.getDecryptionKey()))
|
||||
throw new I2PSessionException("encryption key mismatch");
|
||||
if (getPrivateKey().equals(_primary.getPrivateKey()))
|
||||
throw new I2PSessionException("signing key must differ");
|
||||
// state management
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported in a subsession.
|
||||
* @throws UnsupportedOperationException always
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public I2PSession addSubsession(InputStream destKeyStream, Properties opts) throws I2PSessionException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsupported in a subsession.
|
||||
* Does nothing.
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public void removeSubsession(I2PSession session) {}
|
||||
|
||||
/**
|
||||
* Unsupported in a subsession.
|
||||
* @return empty list always
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public List<I2PSession> getSubsessions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing for now
|
||||
*/
|
||||
@Override
|
||||
public void updateOptions(Properties options) {}
|
||||
|
||||
/**
|
||||
* Connect to the router and establish a session. This call blocks until
|
||||
* a session is granted.
|
||||
*
|
||||
* Should be threadsafe, other threads will block until complete.
|
||||
* Disconnect / destroy from another thread may be called simultaneously and
|
||||
* will (should?) interrupt the connect.
|
||||
*
|
||||
* @throws I2PSessionException if there is a configuration error or the router is
|
||||
* not reachable
|
||||
*/
|
||||
@Override
|
||||
public void connect() throws I2PSessionException {
|
||||
synchronized(_stateLock) {
|
||||
if (_state != State.OPEN) {
|
||||
_state = State.OPENING;
|
||||
}
|
||||
}
|
||||
_primary.connect();
|
||||
synchronized(_stateLock) {
|
||||
if (_state != State.OPEN) {
|
||||
Thread notifier = new I2PAppThread(_availabilityNotifier, "ClientNotifier " + getPrefix(), true);
|
||||
notifier.start();
|
||||
_state = State.OPEN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the session been closed (or not yet connected)?
|
||||
* False when open and during transitions.
|
||||
*/
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
// FIXME
|
||||
return super.isClosed() || _primary.isClosed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deliver an I2CP message to the router
|
||||
* May block for several seconds if the write queue to the router is full
|
||||
*
|
||||
* @throws I2PSessionException if the message is malformed or there is an error writing it out
|
||||
*/
|
||||
@Override
|
||||
void sendMessage(I2CPMessage message) throws I2PSessionException {
|
||||
// workaround for now, as primary will send out our CreateSession
|
||||
// from his connect, while we are still closed.
|
||||
// If we did it in connect() we wouldn't need this
|
||||
if (isClosed() &&
|
||||
message.getType() != CreateSessionMessage.MESSAGE_TYPE &&
|
||||
message.getType() != CreateLeaseSetMessage.MESSAGE_TYPE)
|
||||
throw new I2PSessionException("Already closed");
|
||||
_primary.sendMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass off the error to the listener
|
||||
* Misspelled, oh well.
|
||||
* @param error non-null
|
||||
*/
|
||||
@Override
|
||||
void propogateError(String msg, Throwable error) {
|
||||
_primary.propogateError(msg, error);
|
||||
if (_sessionListener != null) _sessionListener.errorOccurred(this, msg, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tear down the session, and do NOT reconnect.
|
||||
*
|
||||
* Blocks if session has not been fully started.
|
||||
*/
|
||||
@Override
|
||||
public void destroySession() {
|
||||
_primary.destroySession();
|
||||
if (_availabilityNotifier != null)
|
||||
_availabilityNotifier.stopNotifying();
|
||||
if (_sessionListener != null) _sessionListener.disconnected(this);
|
||||
changeState(State.CLOSED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will interrupt a connect in progress.
|
||||
*/
|
||||
@Override
|
||||
protected void disconnect() {
|
||||
_primary.disconnect();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean reconnect() {
|
||||
return _primary.reconnect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the message handler
|
||||
* on reception of DestReplyMessage
|
||||
*
|
||||
* This will never happen, as the dest reply message does not contain a session ID.
|
||||
*/
|
||||
@Override
|
||||
void destReceived(Destination d) {
|
||||
_primary.destReceived(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the message handler
|
||||
* on reception of DestReplyMessage
|
||||
*
|
||||
* This will never happen, as the dest reply message does not contain a session ID.
|
||||
*
|
||||
* @param h non-null
|
||||
*/
|
||||
@Override
|
||||
void destLookupFailed(Hash h) {
|
||||
_primary.destLookupFailed(h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the message handler
|
||||
* on reception of HostReplyMessage
|
||||
* @param d non-null
|
||||
*/
|
||||
void destReceived(long nonce, Destination d) {
|
||||
_primary.destReceived(nonce, d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the message handler
|
||||
* on reception of HostReplyMessage
|
||||
*/
|
||||
@Override
|
||||
void destLookupFailed(long nonce) {
|
||||
_primary.destLookupFailed(nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the message handler.
|
||||
* This will never happen, as the bw limits message does not contain a session ID.
|
||||
*/
|
||||
@Override
|
||||
void bwReceived(int[] i) {
|
||||
_primary.bwReceived(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking. Waits a max of 10 seconds by default.
|
||||
* See lookupDest with maxWait parameter to change.
|
||||
* Implemented in 0.8.3 in I2PSessionImpl;
|
||||
* previously was available only in I2PSimpleSession.
|
||||
* Multiple outstanding lookups are now allowed.
|
||||
* @return null on failure
|
||||
*/
|
||||
@Override
|
||||
public Destination lookupDest(Hash h) throws I2PSessionException {
|
||||
return _primary.lookupDest(h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blocking.
|
||||
* @param maxWait ms
|
||||
* @return null on failure
|
||||
*/
|
||||
@Override
|
||||
public Destination lookupDest(Hash h, long maxWait) throws I2PSessionException {
|
||||
return _primary.lookupDest(h, maxWait);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the router to lookup a Destination by host name.
|
||||
* Blocking. Waits a max of 10 seconds by default.
|
||||
*
|
||||
* This only makes sense for a b32 hostname, OR outside router context.
|
||||
* Inside router context, just query the naming service.
|
||||
* Outside router context, this does NOT query the context naming service.
|
||||
* Do that first if you expect a local addressbook.
|
||||
*
|
||||
* This will log a warning for non-b32 in router context.
|
||||
*
|
||||
* See interface for suggested implementation.
|
||||
*
|
||||
* Requires router side to be 0.9.11 or higher. If the router is older,
|
||||
* this will return null immediately.
|
||||
*/
|
||||
@Override
|
||||
public Destination lookupDest(String name) throws I2PSessionException {
|
||||
return _primary.lookupDest(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the router to lookup a Destination by host name.
|
||||
* Blocking. See above for details.
|
||||
* @param maxWait ms
|
||||
* @return null on failure
|
||||
*/
|
||||
@Override
|
||||
public Destination lookupDest(String name, long maxWait) throws I2PSessionException {
|
||||
return _primary.lookupDest(name, maxWait);
|
||||
}
|
||||
|
||||
/**
|
||||
* This may not work???????????, as the reply does not contain a session ID, so
|
||||
* it won't be routed back to us?
|
||||
*/
|
||||
@Override
|
||||
public int[] bandwidthLimits() throws I2PSessionException {
|
||||
return _primary.bandwidthLimits();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateActivity() {
|
||||
_primary.updateActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long lastActivity() {
|
||||
return _primary.lastActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReduced() {
|
||||
_primary.setReduced();
|
||||
}
|
||||
}
|
@ -38,6 +38,11 @@ public class CreateLeaseSetMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -32,6 +32,16 @@ public class DestroySessionMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -76,6 +76,16 @@ public class HostLookupMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 to 2**32 - 1
|
||||
*/
|
||||
|
@ -73,6 +73,16 @@ public class HostReplyMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 to 2**32 - 1
|
||||
*/
|
||||
|
@ -60,9 +60,20 @@ public interface I2CPMessage extends DataStructure {
|
||||
public void writeMessage(OutputStream out) throws I2CPMessageException, IOException;
|
||||
|
||||
/**
|
||||
* Return the unique identifier for this type of APIMessage, as specified in the
|
||||
* Return the unique identifier for this type of message, as specified in the
|
||||
* network specification document under #ClientAccessLayerMessages
|
||||
* @return unique identifier for this type of APIMessage
|
||||
* @return unique identifier for this type of message
|
||||
*/
|
||||
public int getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this type of message.
|
||||
* Most but not all message types include a SessionId.
|
||||
* The ones that do already define getSessionId(), but some return a SessionId and
|
||||
* some return a long, so we define a new method here.
|
||||
*
|
||||
* @return SessionId or null if this message type does not include a SessionId
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public SessionId sessionId();
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ package net.i2p.data.i2cp;
|
||||
import net.i2p.I2PException;
|
||||
|
||||
/**
|
||||
* Represent an error serializing or deserializing an APIMessage
|
||||
* Represent an error serializing or deserializing a message
|
||||
*
|
||||
* @author jrandom
|
||||
*/
|
||||
|
@ -127,4 +127,15 @@ public abstract class I2CPMessageImpl extends DataStructureImpl implements I2CPM
|
||||
throw new DataFormatException("Error writing the message", ime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this type of message.
|
||||
* Most but not all message types include a SessionId.
|
||||
* The ones that do already define getSessionId(), but some return a SessionId and
|
||||
* some return a long, so we define a new method here.
|
||||
*
|
||||
* @return null always. Extending classes with a SessionId must override.
|
||||
* @since 0.9.19
|
||||
*/
|
||||
public SessionId sessionId() { return null; }
|
||||
}
|
||||
|
@ -37,6 +37,16 @@ public class MessagePayloadMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId >= 0 ? new SessionId(_sessionId) : null;
|
||||
}
|
||||
|
||||
/** @param id 0-65535 */
|
||||
public void setSessionId(long id) {
|
||||
_sessionId = (int) id;
|
||||
|
@ -193,6 +193,16 @@ public class MessageStatusMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId >= 0 ? new SessionId(_sessionId) : null;
|
||||
}
|
||||
|
||||
/** @param id 0-65535 */
|
||||
public void setSessionId(long id) {
|
||||
_sessionId = (int) id;
|
||||
@ -275,6 +285,12 @@ public class MessageStatusMessage extends I2CPMessageImpl {
|
||||
return "GUARANTEED SUCCESS ";
|
||||
case STATUS_SEND_SUCCESS_LOCAL:
|
||||
return "LOCAL SUCCESS ";
|
||||
case STATUS_SEND_BEST_EFFORT_FAILURE:
|
||||
return "PROBABLE FAILURE ";
|
||||
case STATUS_SEND_FAILURE_NO_TUNNELS:
|
||||
return "NO LOCAL TUNNELS ";
|
||||
case STATUS_SEND_FAILURE_NO_LEASESET:
|
||||
return "LEASESET NOT FOUND ";
|
||||
default:
|
||||
return "SEND FAILURE CODE: " + status;
|
||||
}
|
||||
|
@ -36,6 +36,16 @@ public class ReceiveMessageBeginMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId >= 0 ? new SessionId(_sessionId) : null;
|
||||
}
|
||||
|
||||
/** @param id 0-65535 */
|
||||
public void setSessionId(long id) {
|
||||
_sessionId = (int) id;
|
||||
|
@ -35,6 +35,16 @@ public class ReceiveMessageEndMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId >= 0 ? new SessionId(_sessionId) : null;
|
||||
}
|
||||
|
||||
/** @param id 0-65535 */
|
||||
public void setSessionId(long id) {
|
||||
_sessionId = (int) id;
|
||||
|
@ -33,6 +33,16 @@ public class ReconfigureSessionMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -35,6 +35,16 @@ public class ReportAbuseMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -45,6 +45,16 @@ public class RequestLeaseSetMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -55,6 +55,16 @@ public class RequestVariableLeaseSetMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -38,6 +38,16 @@ public class SendMessageMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
@ -42,6 +42,16 @@ public class SessionStatusMessage extends I2CPMessageImpl {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SessionId for this message.
|
||||
*
|
||||
* @since 0.9.19
|
||||
*/
|
||||
@Override
|
||||
public SessionId sessionId() {
|
||||
return _sessionId;
|
||||
}
|
||||
|
||||
public void setSessionId(SessionId id) {
|
||||
_sessionId = id;
|
||||
}
|
||||
|
Reference in New Issue
Block a user