I2CP: Ensure that callbacks are called on abnormal close

throw IAE on invalid listener protocol/port
log tweaks
This commit is contained in:
zzz
2019-06-22 16:58:44 +00:00
parent 1a030c3f92
commit b99f239f3d
5 changed files with 68 additions and 17 deletions

View File

@ -23,6 +23,7 @@ import net.i2p.util.Log;
* messageAvailable() only calls one listener, not all that apply. * messageAvailable() only calls one listener, not all that apply.
* The others call all listeners. * The others call all listeners.
* *
* @since 0.7.1
* @author zzz * @author zzz
*/ */
public class I2PSessionDemultiplexer implements I2PSessionMuxedListener { public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
@ -31,7 +32,7 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
public I2PSessionDemultiplexer(I2PAppContext ctx) { public I2PSessionDemultiplexer(I2PAppContext ctx) {
_log = ctx.logManager().getLog(I2PSessionDemultiplexer.class); _log = ctx.logManager().getLog(I2PSessionDemultiplexer.class);
_listeners = new ConcurrentHashMap<Integer, I2PSessionMuxedListener>(); _listeners = new ConcurrentHashMap<Integer, I2PSessionMuxedListener>(4);
} }
/** unused */ /** unused */
@ -39,9 +40,9 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport ) { public void messageAvailable(I2PSession session, int msgId, long size, int proto, int fromport, int toport ) {
I2PSessionMuxedListener l = findListener(proto, toport); I2PSessionMuxedListener l = findListener(proto, toport);
if (l != null) if (l != null) {
l.messageAvailable(session, msgId, size, proto, fromport, toport); l.messageAvailable(session, msgId, size, proto, fromport, toport);
else { } else {
// no listener, throw it out // no listener, throw it out
if (_listeners.isEmpty()) { if (_listeners.isEmpty()) {
if (_log.shouldLog(Log.WARN)) if (_log.shouldLog(Log.WARN))
@ -58,18 +59,25 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
} }
public void reportAbuse(I2PSession session, int severity) { public void reportAbuse(I2PSession session, int severity) {
for (I2PSessionMuxedListener l : _listeners.values()) for (I2PSessionMuxedListener l : _listeners.values()) {
l.reportAbuse(session, severity); l.reportAbuse(session, severity);
}
} }
public void disconnected(I2PSession session) { public void disconnected(I2PSession session) {
for (I2PSessionMuxedListener l : _listeners.values()) for (I2PSessionMuxedListener l : _listeners.values()) {
if (_log.shouldInfo())
_log.info("Sending disconnected() to " + l);
l.disconnected(session); l.disconnected(session);
}
} }
public void errorOccurred(I2PSession session, String message, Throwable error) { public void errorOccurred(I2PSession session, String message, Throwable error) {
for (I2PSessionMuxedListener l : _listeners.values()) for (I2PSessionMuxedListener l : _listeners.values()) {
if (_log.shouldInfo())
_log.info("Sending errorOccurred() \"" + message + "\" to " + l);
l.errorOccurred(session, message, error); l.errorOccurred(session, message, error);
}
} }
/** /**
@ -78,6 +86,10 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
* (Streaming lib) * (Streaming lib)
*/ */
public void addListener(I2PSessionListener l, int proto, int port) { public void addListener(I2PSessionListener l, int proto, int port) {
if (proto < 0 || proto > 254 || port < 0 || port > 65535)
throw new IllegalArgumentException();
if (_log.shouldInfo())
_log.info("Old addListener() " + l + ' ' + proto + ' ' + port);
I2PSessionListener old = _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)) if (old != null && _log.shouldLog(Log.WARN))
_log.warn("Listener " + l + " replaces " + old + " for proto: " + proto + " port: " + port); _log.warn("Listener " + l + " replaces " + old + " for proto: " + proto + " port: " + port);
@ -88,12 +100,20 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener {
* UDP perhaps * UDP perhaps
*/ */
public void addMuxedListener(I2PSessionMuxedListener l, int proto, int port) { public void addMuxedListener(I2PSessionMuxedListener l, int proto, int port) {
if (proto < 0 || proto > 254 || port < 0 || port > 65535)
throw new IllegalArgumentException();
if (_log.shouldInfo())
_log.info("addMuxedListener() " + l + ' ' + proto + ' ' + port);
I2PSessionListener old = _listeners.put(key(proto, port), l); I2PSessionListener old = _listeners.put(key(proto, port), l);
if (old != null && _log.shouldLog(Log.WARN)) if (old != null && _log.shouldLog(Log.WARN))
_log.warn("Listener " + l + " replaces " + old + " for proto: " + proto + " port: " + port); _log.warn("Listener " + l + " replaces " + old + " for proto: " + proto + " port: " + port);
} }
public void removeListener(int proto, int port) { public void removeListener(int proto, int port) {
if (proto < 0 || proto > 254 || port < 0 || port > 65535)
throw new IllegalArgumentException();
if (_log.shouldInfo())
_log.info("removeListener() " + proto + ' ' + port);
_listeners.remove(key(proto, port)); _listeners.remove(key(proto, port));
} }

View File

@ -1115,12 +1115,14 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
/** /**
* The I2CPMessageEventListener callback. * The I2CPMessageEventListener callback.
* Recieve notifiation of an error reading the I2CP stream. * Recieve notifiation of an error reading the I2CP stream.
* As of 0.9.41, does NOT call sessionlistener.disconnected(),
* the I2CPMessageReader will call disconnected() also.
*
* @param reader unused * @param reader unused
* @param error non-null * @param error non-null
*/ */
public void readError(I2CPMessageReader reader, Exception error) { public void readError(I2CPMessageReader reader, Exception error) {
propogateError("There was an error reading data", error); propogateError("There was an error reading data", error);
disconnect();
} }
/** /**
@ -1160,7 +1162,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
* Retrieve the configuration options, filtered. * Retrieve the configuration options, filtered.
* All defaults passed in via constructor have been promoted to the primary map. * All defaults passed in via constructor have been promoted to the primary map.
* *
* @return non-null, if insantiated with null options, this will be the System properties. * @return non-null, if instantiated with null options, this will be the System properties.
*/ */
Properties getOptions() { return _options; } Properties getOptions() { return _options; }
@ -1257,6 +1259,8 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
/** /**
* Pass off the error to the listener * Pass off the error to the listener
* Misspelled, oh well. * Misspelled, oh well.
* Calls sessionlistener.errorOccurred()
*
* @param error non-null * @param error non-null
*/ */
void propogateError(String msg, Throwable error) { void propogateError(String msg, Throwable error) {
@ -1292,6 +1296,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
* Tear down the session, and do NOT reconnect. * Tear down the session, and do NOT reconnect.
* *
* Will interrupt an open in progress. * Will interrupt an open in progress.
* Calls sessionlistener.disconnected()
*/ */
public void destroySession(boolean sendDisconnect) { public void destroySession(boolean sendDisconnect) {
synchronized(_stateLock) { synchronized(_stateLock) {
@ -1379,15 +1384,16 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
/** /**
* The I2CPMessageEventListener callback. * The I2CPMessageEventListener callback.
* Recieve notification that the I2CP connection was disconnected. * Recieve notification that the I2CP connection was disconnected.
* Calls sessionlistener.disconnected()
* @param reader unused * @param reader unused
*/ */
public void disconnected(I2CPMessageReader reader) { public void disconnected(I2CPMessageReader reader) {
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Disconnected", new Exception("Disconnected"));
disconnect(); disconnect();
} }
/** /**
* Will interrupt a connect in progress. * Will interrupt a connect in progress.
* Calls sessionlistener.disconnected()
*/ */
protected void disconnect() { protected void disconnect() {
State oldState; State oldState;
@ -1397,7 +1403,9 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
oldState = _state; oldState = _state;
changeState(State.CLOSING); changeState(State.CLOSING);
} }
if (_log.shouldLog(Log.DEBUG)) _log.debug(getPrefix() + "Disconnect() called", new Exception("Disconnect")); if (_log.shouldWarn())
_log.warn(getPrefix() + "Disconnected", new Exception("Disconnected"));
if (_sessionListener != null) _sessionListener.disconnected(this);
// don't try to reconnect if it failed before GETTDATE // don't try to reconnect if it failed before GETTDATE
if (oldState != State.OPENING && shouldReconnect()) { if (oldState != State.OPENING && shouldReconnect()) {
if (reconnect()) { if (reconnect()) {
@ -1409,7 +1417,6 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
if (_log.shouldLog(Log.ERROR)) if (_log.shouldLog(Log.ERROR))
_log.error(getPrefix() + "Disconned from the router, and not trying to reconnect"); _log.error(getPrefix() + "Disconned from the router, and not trying to reconnect");
if (_sessionListener != null) _sessionListener.disconnected(this);
closeSocket(); closeSocket();
changeState(State.CLOSED); changeState(State.CLOSED);
@ -1459,7 +1466,6 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
protected String getPrefix() { protected String getPrefix() {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
buf.append('['); buf.append('[');
buf.append(_state.toString()).append(' ');
String s = _options.getProperty("inbound.nickname"); String s = _options.getProperty("inbound.nickname");
if (s != null) if (s != null)
buf.append(s); buf.append(s);
@ -1468,6 +1474,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2
SessionId id = _sessionId; SessionId id = _sessionId;
if (id != null) if (id != null)
buf.append(" #").append(id.getSessionId()); buf.append(" #").append(id.getSessionId());
buf.append('(').append(_state.toString()).append(')');
buf.append("]: "); buf.append("]: ");
return buf.toString(); return buf.toString();
} }

View File

@ -109,7 +109,7 @@ public class I2CPMessageReader {
/** /**
* Notify the listener that an exception was thrown while reading from the given * Notify the listener that an exception was thrown while reading from the given
* reader * reader. For most errors, disconnected() will also be called, as of 0.9.41.
* *
* @param reader I2CPMessageReader to notify * @param reader I2CPMessageReader to notify
* @param error Exception that was thrown, non-null * @param error Exception that was thrown, non-null
@ -117,8 +117,8 @@ public class I2CPMessageReader {
public void readError(I2CPMessageReader reader, Exception error); public void readError(I2CPMessageReader reader, Exception error);
/** /**
* Notify the listener that the stream the given reader was running off * Notify the listener that the stream this reader was reading was
* closed * closed. For most errors, readError() will be called first, as of 0.9.41
* *
* @param reader I2CPMessageReader to notify * @param reader I2CPMessageReader to notify
*/ */
@ -165,6 +165,7 @@ public class I2CPMessageReader {
} catch (RuntimeException e) { } catch (RuntimeException e) {
_log.log(Log.CRIT, "Uncaught I2CP error", e); _log.log(Log.CRIT, "Uncaught I2CP error", e);
_listener.readError(I2CPMessageReader.this, e); _listener.readError(I2CPMessageReader.this, e);
_listener.disconnected(I2CPMessageReader.this);
cancelRunner(); cancelRunner();
} }
} }
@ -190,6 +191,7 @@ public class I2CPMessageReader {
cancelRunner(); cancelRunner();
} catch (IOException ioe) { } catch (IOException ioe) {
_log.warn("IO Error handling message", ioe); _log.warn("IO Error handling message", ioe);
_listener.readError(I2CPMessageReader.this, ioe);
_listener.disconnected(I2CPMessageReader.this); _listener.disconnected(I2CPMessageReader.this);
cancelRunner(); cancelRunner();
} catch (OutOfMemoryError oom) { } catch (OutOfMemoryError oom) {
@ -197,6 +199,7 @@ public class I2CPMessageReader {
throw oom; throw oom;
} catch (RuntimeException e) { } catch (RuntimeException e) {
_log.log(Log.CRIT, "Unhandled error reading I2CP stream", e); _log.log(Log.CRIT, "Unhandled error reading I2CP stream", e);
_listener.readError(I2CPMessageReader.this, e);
_listener.disconnected(I2CPMessageReader.this); _listener.disconnected(I2CPMessageReader.this);
cancelRunner(); cancelRunner();
} }

View File

@ -1,3 +1,24 @@
2019-06-22 zzz
* Console: New logo
* I2CP: Ensure that callbacks are called on abnormal close
2019-06-21 zzz
* Transport: Update hidden mode country list
2019-06-18 zzz
* i2ptunnel: Improve logging when no outproxy configured (ticket #2338)
* Reseed: Remove atomike
2019-06-17 zzz
* Console: Hide news section in summary bar if
news fetching is disabled (ticket #2301)
* Router: Don't check for ping file at startup on Android
2019-06-16 zzz
* i2psnark:
- Increase DHT blacklist time (ticket #2275)
- Fix QupZilla detection (ticket #2026)
2019-06-15 zzz 2019-06-15 zzz
* Console: Fix stopping webapps at shutdown (ticket #2508) * Console: Fix stopping webapps at shutdown (ticket #2508)

View File

@ -18,10 +18,10 @@ public class RouterVersion {
/** deprecated */ /** deprecated */
public final static String ID = "Monotone"; public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION; public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 11; public final static long BUILD = 12;
/** for example "-test" */ /** for example "-test" */
public final static String EXTRA = ""; public final static String EXTRA = "-rc";
public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA;
public static void main(String args[]) { public static void main(String args[]) {
System.out.println("I2P Router version: " + FULL_VERSION); System.out.println("I2P Router version: " + FULL_VERSION);