diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index a0a68aa43b5429eb2a76a023a9a1e07f0d8da2a9..2d4d7e0dd06f13eca77b71032beb39c9f4b2b491 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -77,6 +77,16 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna private volatile ThreadPoolExecutor _executor; + /** this is ONLY for shared clients */ + private static I2PSocketManager socketManager; + + /** + * Only destroy and replace a static shared client socket manager if it's been connected before + * @since 0.9.20 + */ + private enum SocketManagerState { INIT, CONNECTED } + private static SocketManagerState _socketManagerState = SocketManagerState.INIT; + public static final String PROP_USE_SSL = I2PTunnelServer.PROP_USE_SSL; /** @@ -239,10 +249,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna connectManager(); } - /** this is ONLY for shared clients */ - private static I2PSocketManager socketManager; - - /** * This is ONLY for shared clients. * As of 0.9.20 this is fast, and does NOT connect the manager to the router. @@ -283,12 +289,13 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna Log _log = tunnel.getContext().logManager().getLog(I2PTunnelClientBase.class); if (socketManager != null && !socketManager.isDestroyed()) { I2PSession s = socketManager.getSession(); - if (s.isClosed()) { + if (s.isClosed() && _socketManagerState != SocketManagerState.INIT) { if (_log.shouldLog(Log.INFO)) _log.info(tunnel.getClientOptions().getProperty("inbound.nickname") + ": Building a new socket manager since the old one closed [s=" + s + "]"); tunnel.removeSession(s); // make sure the old one is closed socketManager.destroySocketManager(); + _socketManagerState = SocketManagerState.INIT; // We could be here a LONG time, holding the lock socketManager = buildSocketManager(tunnel, pkf); } else { @@ -424,6 +431,10 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna while (sockMgr.getSession().isClosed()) { try { sockMgr.getSession().connect(); + synchronized(I2PTunnelClientBase.class) { + if (sockMgr == socketManager) + _socketManagerState = SocketManagerState.CONNECTED; + } } catch (I2PSessionException ise) { // shadows instance _log Log _log = getTunnel().getContext().logManager().getLog(I2PTunnelClientBase.class); diff --git a/core/java/src/net/i2p/client/I2PSession.java b/core/java/src/net/i2p/client/I2PSession.java index da67e2c02c0bf9601736f84c3abf353155cb6e2f..a6ce4122ee712af166dbcf90aeacd7489930f79a 100644 --- a/core/java/src/net/i2p/client/I2PSession.java +++ b/core/java/src/net/i2p/client/I2PSession.java @@ -257,7 +257,7 @@ public interface I2PSession { /** * Have we closed the session? * - * @return true if the session is closed + * @return true if the session is closed, OR connect() has not been called yet */ public boolean isClosed(); diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index cd6154c96ad5928eddd19b2a01ab755b14e4c731..7527dd8862e04b860a327a434ef06e57379e12a9 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -135,7 +135,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 CLOSED } - private State _state = State.INIT; + protected State _state = State.INIT; protected final Object _stateLock = new Object(); /** @@ -614,7 +614,12 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 * Report abuse with regards to the given messageId */ public void reportAbuse(int msgId, int severity) throws I2PSessionException { - if (isClosed()) throw new I2PSessionException(getPrefix() + "Already closed"); + synchronized (_stateLock) { + if (_state == State.CLOSED) + throw new I2PSessionException("Already closed"); + if (_state == State.INIT) + throw new I2PSessionException("Not open, must call connect() first"); + } _producer.reportAbuse(this, msgId, severity); } diff --git a/core/java/src/net/i2p/client/I2PSessionImpl2.java b/core/java/src/net/i2p/client/I2PSessionImpl2.java index 9f8a5465d31184b14239f1dc49726688b9b2b39a..5cd2b930c4295776e164815acce960a22f6ae9d4 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl2.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl2.java @@ -247,7 +247,12 @@ class I2PSessionImpl2 extends I2PSessionImpl { public boolean sendMessage(Destination dest, byte[] payload, int offset, int size, SessionKey keyUsed, Set tagsSent, long expires) throws I2PSessionException { if (_log.shouldLog(Log.DEBUG)) _log.debug("sending message"); - if (isClosed()) throw new I2PSessionException("Already closed"); + synchronized (_stateLock) { + if (_state == State.CLOSED) + throw new I2PSessionException("Already closed"); + if (_state == State.INIT) + throw new I2PSessionException("Not open, must call connect() first"); + } updateActivity(); // Sadly there is no way to send something completely uncompressed in a backward-compatible way, diff --git a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java index 48ca6016e8c963ee400cc7f12d08bfd2fce09d7c..0185496aa3aceea641ed8b587274bcdb5b68edd2 100644 --- a/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionMuxedImpl.java @@ -256,7 +256,12 @@ class I2PSessionMuxedImpl extends I2PSessionImpl2 { * @since 0.9.14 */ private byte[] prepPayload(byte[] payload, int offset, int size, int proto, int fromPort, int toPort) throws I2PSessionException { - if (isClosed()) throw new I2PSessionException("Already closed"); + synchronized (_stateLock) { + if (_state == State.CLOSED) + throw new I2PSessionException("Already closed"); + if (_state == State.INIT) + throw new I2PSessionException("Not open, must call connect() first"); + } updateActivity(); if (shouldCompress(size)) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 0cd02d33d12e8a5cbd5776e89fe01dcb65d8b49b..5fd579e05b82a079d03afc83109a625c6e423097 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 29; + public final static long BUILD = 30; /** for example "-test" */ public final static String EXTRA = "-rc";