* Fixed race that (maybe) caused the problems reported by aum on

<http://dev.i2p.net/pipermail/i2p/2004-April/000214.html>;
* slightly revised locking;
* made accept() throw a ConnectException when the I2PServerSocket is closed.
(human)
This commit is contained in:
human
2004-04-14 15:28:02 +00:00
committed by zzz
parent 4cdd42f391
commit d2b09ecfda
2 changed files with 50 additions and 24 deletions

View File

@ -1,5 +1,7 @@
package net.i2p.client.streaming; package net.i2p.client.streaming;
import java.net.ConnectException;
import net.i2p.I2PException; import net.i2p.I2PException;
/** /**
@ -17,10 +19,13 @@ public interface I2PServerSocket {
* connection and the local application wasn't .accept()ing new connections, * connection and the local application wasn't .accept()ing new connections,
* they should get refused (if .accept() doesnt occur in some small period) * they should get refused (if .accept() doesnt occur in some small period)
* *
* @return a connected I2PSocket
*
* @throws I2PException if there is a problem with reading a new socket * @throws I2PException if there is a problem with reading a new socket
* from the data available (aka the I2PSession closed, etc) * from the data available (aka the I2PSession closed, etc)
* @throws ConnectException if the I2PServerSocket is closed
*/ */
public I2PSocket accept() throws I2PException; public I2PSocket accept() throws I2PException, ConnectException;
/** /**
* Access the manager which is coordinating the server socket * Access the manager which is coordinating the server socket

View File

@ -1,5 +1,7 @@
package net.i2p.client.streaming; package net.i2p.client.streaming;
import java.net.ConnectException;
import net.i2p.I2PException; import net.i2p.I2PException;
import net.i2p.util.Log; import net.i2p.util.Log;
@ -12,42 +14,61 @@ class I2PServerSocketImpl implements I2PServerSocket {
private I2PSocketManager mgr; private I2PSocketManager mgr;
private I2PSocket cached = null; // buffer one socket here private I2PSocket cached = null; // buffer one socket here
private boolean closing = false; // Are we being closed?
private Object acceptLock = new Object();
public I2PServerSocketImpl(I2PSocketManager mgr) { public I2PServerSocketImpl(I2PSocketManager mgr) {
this.mgr = mgr; this.mgr = mgr;
} }
public synchronized I2PSocket accept() throws I2PException { public synchronized I2PSocket accept() throws I2PException, ConnectException {
while (cached == null) { I2PSocket ret;
synchronized (acceptLock) {
while ((cached == null) && !closing) {
myWait(); myWait();
} }
I2PSocket ret = cached;
if (closing) {
throw new ConnectException("I2PServerSocket closed");
}
ret = cached;
cached = null; cached = null;
notifyAll(); acceptLock.notifyAll();
}
_log.debug("TIMING: handed out accept result " + ret.hashCode()); _log.debug("TIMING: handed out accept result " + ret.hashCode());
return ret; return ret;
} }
public synchronized boolean getNewSocket(I2PSocket s) { public boolean getNewSocket(I2PSocket s) {
synchronized (acceptLock) {
while (cached != null) { while (cached != null) {
myWait(); myWait();
} }
cached = s; cached = s;
notifyAll(); acceptLock.notifyAll();
}
return true; return true;
} }
public void close() throws I2PException { public void close() throws I2PException {
//noop synchronized (acceptLock) {
} closing = true;
acceptLock.notifyAll();
private void myWait() {
try {
wait();
} catch (InterruptedException ex) {
} }
} }
public I2PSocketManager getManager() { public I2PSocketManager getManager() {
return mgr; return mgr;
} }
private void myWait() {
try {
acceptLock.wait();
} catch (InterruptedException ex) {}
}
} }