diff --git a/core/java/src/net/i2p/client/I2PSessionImpl.java b/core/java/src/net/i2p/client/I2PSessionImpl.java index 597c0af36..7a9ae46c5 100644 --- a/core/java/src/net/i2p/client/I2PSessionImpl.java +++ b/core/java/src/net/i2p/client/I2PSessionImpl.java @@ -125,6 +125,8 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 * @since 0.9.8 */ protected enum State { + /** @since 0.9.20 */ + INIT, OPENING, /** @since 0.9.11 */ GOTDATE, @@ -133,7 +135,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 CLOSED } - private State _state = State.CLOSED; + private State _state = State.INIT; protected final Object _stateLock = new Object(); /** @@ -434,6 +436,9 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 boolean loop = true; while (loop) { switch (_state) { + case INIT: + loop = false; + break; case CLOSED: if (wasOpening) throw new I2PSessionException("connect by other thread failed"); @@ -581,8 +586,8 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 synchronized(_stateLock) { if (_state == State.GOTDATE) break; - if (_state != State.OPENING) - throw new IOException("Socket closed"); + if (_state != State.OPENING && _state != State.INIT) + throw new IOException("Socket closed, state=" + _state); // InterruptedException caught by caller _stateLock.wait(1000); } @@ -815,7 +820,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 /** * Has the session been closed (or not yet connected)? - * False when open and during transitions. Unsynchronized. + * False when open and during transitions. Synchronized. */ public boolean isClosed() { synchronized (_stateLock) { @@ -885,7 +890,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 */ public void destroySession(boolean sendDisconnect) { synchronized(_stateLock) { - if (_state == State.CLOSING || _state == State.CLOSED) + if (_state == State.CLOSING || _state == State.CLOSED || _state == State.INIT) return; changeState(State.CLOSING); } @@ -965,7 +970,7 @@ public abstract class I2PSessionImpl implements I2PSession, I2CPMessageReader.I2 protected void disconnect() { State oldState; synchronized(_stateLock) { - if (_state == State.CLOSING || _state == State.CLOSED) + if (_state == State.CLOSING || _state == State.CLOSED || _state == State.INIT) return; oldState = _state; changeState(State.CLOSING); diff --git a/history.txt b/history.txt index 9965bd1eb..b18039cfe 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,9 @@ +2015-05-23 zzz + * I2CP: Add an INIT state for session, so a newly created session + isn't treated as CLOSED and immediately replaced by i2ptunnel, + which caused dup shared clients in a race at startup + (possible related tickets #642, #650, #815, #1545) + 2015-05-21 kytv * Updates to geoip.txt and geoipv6.dat.gz based on Maxmind GeoLite Country database from 2015-05-06. @@ -26,7 +32,7 @@ 2015-05-07 zzz * SAM: Close datagram or raw session when underlying - I2P session closes (ticket #1563) + I2P session closes (tickets #1455, #1563) * Update: Add support for su3-signed development builds (ticket #1381) 2015-05-06 zzz diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 33006bcb1..285b64c36 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 = 27; + public final static long BUILD = 28; /** for example "-test" */ public final static String EXTRA = "-rc";