2004-04-08 04:41:54 +00:00
|
|
|
package net.i2p.client.streaming;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.InterruptedIOException;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
|
2004-06-28 13:21:18 +00:00
|
|
|
import net.i2p.I2PAppContext;
|
2004-04-08 04:41:54 +00:00
|
|
|
import net.i2p.I2PException;
|
|
|
|
import net.i2p.client.I2PSessionException;
|
|
|
|
import net.i2p.data.Destination;
|
2004-08-06 22:24:56 +00:00
|
|
|
import net.i2p.util.Clock;
|
2004-04-09 01:22:04 +00:00
|
|
|
import net.i2p.util.I2PThread;
|
2004-04-10 11:39:00 +00:00
|
|
|
import net.i2p.util.Log;
|
2004-04-08 04:41:54 +00:00
|
|
|
|
2004-06-28 13:21:18 +00:00
|
|
|
|
2004-04-08 04:41:54 +00:00
|
|
|
/**
|
|
|
|
* Initial stub implementation for the socket
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
class I2PSocketImpl implements I2PSocket {
|
|
|
|
private final static Log _log = new Log(I2PSocketImpl.class);
|
|
|
|
|
2004-04-10 11:50:11 +00:00
|
|
|
public static final int MAX_PACKET_SIZE = 1024 * 32;
|
|
|
|
public static final int PACKET_DELAY = 100;
|
|
|
|
|
2004-04-08 04:41:54 +00:00
|
|
|
private I2PSocketManager manager;
|
|
|
|
private Destination local;
|
|
|
|
private Destination remote;
|
|
|
|
private String localID;
|
|
|
|
private String remoteID;
|
|
|
|
private Object remoteIDWaiter = new Object();
|
|
|
|
private I2PInputStream in;
|
|
|
|
private I2POutputStream out;
|
2004-05-19 15:14:30 +00:00
|
|
|
private SocketErrorListener _socketErrorListener;
|
2004-04-08 04:41:54 +00:00
|
|
|
private boolean outgoing;
|
2004-05-19 15:14:30 +00:00
|
|
|
private long _socketId;
|
|
|
|
private static long __socketId = 0;
|
|
|
|
private long _bytesRead = 0;
|
|
|
|
private long _bytesWritten = 0;
|
2004-06-28 13:21:18 +00:00
|
|
|
private long _createdOn;
|
|
|
|
private long _closedOn;
|
|
|
|
private long _remoteIdSetTime;
|
2004-08-01 18:34:02 +00:00
|
|
|
private I2PSocketOptions _options;
|
2004-04-08 04:41:54 +00:00
|
|
|
private Object flagLock = new Object();
|
2004-05-07 03:06:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the I2P socket has already been closed.
|
|
|
|
*/
|
|
|
|
private boolean closed = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether to send out a close packet when the socket is
|
|
|
|
* closed. (If the socket is closed because of an incoming close
|
|
|
|
* packet, we need not send one.)
|
|
|
|
*/
|
|
|
|
private boolean sendClose = true;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Whether the I2P socket has already been closed and all data
|
|
|
|
* (from I2P to the app, dunno whether to call this incoming or
|
|
|
|
* outgoing) has been processed.
|
|
|
|
*/
|
|
|
|
private boolean closed2 = false;
|
2004-04-10 11:50:11 +00:00
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* @param peer who this socket is (or should be) connected to
|
|
|
|
* @param mgr how we talk to the network
|
|
|
|
* @param outgoing did we initiate the connection (true) or did we receive it (false)?
|
|
|
|
* @param localID what is our half of the socket ID?
|
|
|
|
*/
|
2004-04-10 11:50:11 +00:00
|
|
|
public I2PSocketImpl(Destination peer, I2PSocketManager mgr, boolean outgoing, String localID) {
|
|
|
|
this.outgoing = outgoing;
|
|
|
|
manager = mgr;
|
|
|
|
remote = peer;
|
2004-05-19 15:14:30 +00:00
|
|
|
_socketId = ++__socketId;
|
2004-04-10 11:50:11 +00:00
|
|
|
local = mgr.getSession().getMyDestination();
|
|
|
|
in = new I2PInputStream();
|
|
|
|
I2PInputStream pin = new I2PInputStream();
|
|
|
|
out = new I2POutputStream(pin);
|
|
|
|
new I2PSocketRunner(pin);
|
|
|
|
this.localID = localID;
|
2004-06-28 13:21:18 +00:00
|
|
|
_createdOn = I2PAppContext.getGlobalContext().clock().now();
|
|
|
|
_remoteIdSetTime = -1;
|
|
|
|
_closedOn = -1;
|
2004-08-01 18:34:02 +00:00
|
|
|
_options = mgr.getDefaultOptions();
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* Our half of the socket's unique ID
|
|
|
|
*
|
|
|
|
*/
|
2004-04-08 04:41:54 +00:00
|
|
|
public String getLocalID() {
|
2004-04-10 11:50:11 +00:00
|
|
|
return localID;
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* We've received the other side's half of the socket's unique ID
|
|
|
|
*/
|
2004-04-08 04:41:54 +00:00
|
|
|
public void setRemoteID(String id) {
|
2004-04-10 11:50:11 +00:00
|
|
|
synchronized (remoteIDWaiter) {
|
|
|
|
remoteID = id;
|
2004-06-28 13:21:18 +00:00
|
|
|
_remoteIdSetTime = System.currentTimeMillis();
|
2004-04-10 11:50:11 +00:00
|
|
|
remoteIDWaiter.notifyAll();
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* Retrieve the other side's half of the socket's unique ID, or null if it
|
|
|
|
* isn't known yet
|
|
|
|
*
|
|
|
|
* @param wait if true, we should wait until we receive it from the peer, otherwise
|
|
|
|
* return what we know immediately (which may be null)
|
|
|
|
*/
|
|
|
|
public String getRemoteID(boolean wait) {
|
|
|
|
try {
|
|
|
|
return getRemoteID(wait, -1);
|
|
|
|
} catch (InterruptedIOException iie) {
|
|
|
|
_log.error("wtf, we said we didn't want it to time out! you smell", iie);
|
|
|
|
return null;
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* Retrieve the other side's half of the socket's unique ID, or null if it isn't
|
|
|
|
* known yet and we were instructed not to wait
|
|
|
|
*
|
|
|
|
* @param wait should we wait for the peer to send us their half of the ID, or
|
|
|
|
* just return immediately?
|
|
|
|
* @param maxWait if we're going to wait, after how long should we timeout and fail?
|
|
|
|
* (if this value is < 0, we wait indefinitely)
|
|
|
|
* @throws InterruptedIOException when the max waiting period has been exceeded
|
|
|
|
*/
|
2004-04-08 04:41:54 +00:00
|
|
|
public String getRemoteID(boolean wait, long maxWait) throws InterruptedIOException {
|
2004-04-10 11:50:11 +00:00
|
|
|
long dieAfter = System.currentTimeMillis() + maxWait;
|
|
|
|
synchronized (remoteIDWaiter) {
|
2004-04-16 03:31:13 +00:00
|
|
|
if (wait) {
|
2004-06-28 13:21:18 +00:00
|
|
|
if (remoteID == null) {
|
|
|
|
try {
|
|
|
|
if (maxWait >= 0)
|
|
|
|
remoteIDWaiter.wait(maxWait);
|
|
|
|
else
|
|
|
|
remoteIDWaiter.wait();
|
|
|
|
} catch (InterruptedException ex) {
|
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
|
2004-06-27 19:39:45 +00:00
|
|
|
long now = System.currentTimeMillis();
|
|
|
|
if ((maxWait >= 0) && (now >= dieAfter)) {
|
|
|
|
long waitedExcess = now - dieAfter;
|
2004-06-28 13:21:18 +00:00
|
|
|
throw new InterruptedIOException("Timed out waiting for remote ID (waited " + waitedExcess
|
|
|
|
+ "ms too long [" + maxWait + "ms, remId " + remoteID
|
|
|
|
+ ", remId set " + (now-_remoteIdSetTime) + "ms ago])");
|
2004-06-27 19:39:45 +00:00
|
|
|
}
|
2004-04-16 03:31:13 +00:00
|
|
|
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("TIMING: RemoteID set to "
|
|
|
|
+ I2PSocketManager.getReadableForm(remoteID) + " for "
|
|
|
|
+ this.hashCode());
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
return remoteID;
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* Retrieve the other side's half of the socket's unique ID, or null if it
|
|
|
|
* isn't known yet. This does not wait
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public String getRemoteID() {
|
2004-04-10 11:50:11 +00:00
|
|
|
return getRemoteID(false);
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
|
|
|
* The other side has given us some data, so inject it into our socket's
|
|
|
|
* inputStream
|
|
|
|
*
|
|
|
|
* @param data the data to inject into our local inputStream
|
|
|
|
*/
|
2004-04-08 04:41:54 +00:00
|
|
|
public void queueData(byte[] data) {
|
2004-05-19 15:14:30 +00:00
|
|
|
_bytesRead += data.length;
|
2004-08-01 18:34:02 +00:00
|
|
|
try {
|
|
|
|
in.queueData(data);
|
|
|
|
} catch (InterruptedIOException iie) {
|
|
|
|
if (_log.shouldLog(Log.ERROR))
|
|
|
|
_log.error("Queue overflow, closing the stream", iie);
|
|
|
|
try {
|
|
|
|
close();
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
if (_log.shouldLog(Log.ERROR))
|
|
|
|
_log.error("Error closing the stream due to overflow", ioe);
|
|
|
|
}
|
|
|
|
} catch (IOException ioe) {
|
|
|
|
if (_log.shouldLog(Log.ERROR))
|
|
|
|
_log.error("Connection closed while writing to the socket", ioe);
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the Destination of this side of the socket.
|
|
|
|
*/
|
2004-04-10 11:50:11 +00:00
|
|
|
public Destination getThisDestination() {
|
|
|
|
return local;
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the destination of the peer.
|
|
|
|
*/
|
2004-04-10 11:50:11 +00:00
|
|
|
public Destination getPeerDestination() {
|
|
|
|
return remote;
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return an InputStream to read from the socket.
|
|
|
|
*/
|
2004-04-10 11:50:11 +00:00
|
|
|
public InputStream getInputStream() throws IOException {
|
|
|
|
if ((in == null)) throw new IOException("Not connected");
|
|
|
|
return in;
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return an OutputStream to write into the socket.
|
|
|
|
*/
|
|
|
|
public OutputStream getOutputStream() throws IOException {
|
2004-04-10 11:50:11 +00:00
|
|
|
if ((out == null)) throw new IOException("Not connected");
|
|
|
|
return out;
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2004-05-07 03:06:41 +00:00
|
|
|
* Closes the socket if not closed yet (from the Application
|
|
|
|
* side).
|
2004-04-08 04:41:54 +00:00
|
|
|
*/
|
|
|
|
public void close() throws IOException {
|
2004-04-10 11:50:11 +00:00
|
|
|
synchronized (flagLock) {
|
2004-06-28 13:21:18 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("Closing connection");
|
2004-04-10 11:50:11 +00:00
|
|
|
closed = true;
|
2004-06-28 13:21:18 +00:00
|
|
|
_closedOn = I2PAppContext.getGlobalContext().clock().now();
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
out.close();
|
|
|
|
in.notifyClosed();
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-07 03:06:41 +00:00
|
|
|
/**
|
|
|
|
* Close the socket from the I2P side, e. g. by a close packet.
|
|
|
|
*/
|
|
|
|
protected void internalClose() {
|
2004-04-10 11:50:11 +00:00
|
|
|
synchronized (flagLock) {
|
|
|
|
closed = true;
|
|
|
|
closed2 = true;
|
|
|
|
sendClose = false;
|
2004-06-28 13:21:18 +00:00
|
|
|
_closedOn = I2PAppContext.getGlobalContext().clock().now();
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
out.close();
|
|
|
|
in.notifyClosed();
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private byte getMask(int add) {
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
if (outgoing)
|
|
|
|
return (byte)(I2PSocketManager.DATA_IN + (byte)add);
|
|
|
|
else
|
|
|
|
return (byte)(I2PSocketManager.DATA_OUT + (byte)add);
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
|
2004-08-01 18:34:02 +00:00
|
|
|
public void setOptions(I2PSocketOptions options) {
|
|
|
|
_options = options;
|
|
|
|
in.setReadTimeout(options.getReadTimeout());
|
|
|
|
}
|
|
|
|
|
|
|
|
public I2PSocketOptions getOptions() {
|
|
|
|
return _options;
|
|
|
|
}
|
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
/**
|
2004-08-01 18:34:02 +00:00
|
|
|
* How long we will wait blocked on a read() operation. This is simply a
|
|
|
|
* helper to query the I2PSocketOptions
|
|
|
|
*
|
|
|
|
* @return milliseconds to wait, or -1 if we will wait indefinitely
|
2004-05-07 01:32:48 +00:00
|
|
|
*/
|
2004-04-21 17:56:16 +00:00
|
|
|
public long getReadTimeout() {
|
2004-08-01 18:34:02 +00:00
|
|
|
return _options.getReadTimeout();
|
2004-04-21 17:56:16 +00:00
|
|
|
}
|
|
|
|
|
2004-08-01 18:34:02 +00:00
|
|
|
/**
|
|
|
|
* Define how long we will wait blocked on a read() operation (-1 will make
|
|
|
|
* the socket wait forever). This is simply a helper to adjust the
|
|
|
|
* I2PSocketOptions
|
|
|
|
*
|
|
|
|
*/
|
2004-04-21 17:56:16 +00:00
|
|
|
public void setReadTimeout(long ms) {
|
2004-08-01 18:34:02 +00:00
|
|
|
_options.setReadTimeout(ms);
|
2004-04-21 17:56:16 +00:00
|
|
|
in.setReadTimeout(ms);
|
|
|
|
}
|
2004-08-01 18:34:02 +00:00
|
|
|
|
2004-05-19 15:14:30 +00:00
|
|
|
public void setSocketErrorListener(SocketErrorListener lsnr) {
|
|
|
|
_socketErrorListener = lsnr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void errorOccurred() {
|
|
|
|
if (_socketErrorListener != null)
|
|
|
|
_socketErrorListener.errorOccurred();
|
|
|
|
}
|
|
|
|
|
2004-06-28 13:21:18 +00:00
|
|
|
public long getBytesSent() { return _bytesWritten; }
|
|
|
|
public long getBytesReceived() { return _bytesRead; }
|
|
|
|
public long getCreatedOn() { return _createdOn; }
|
|
|
|
public long getClosedOn() { return _closedOn; }
|
|
|
|
|
|
|
|
|
2004-05-19 15:14:30 +00:00
|
|
|
private String getPrefix() { return "[" + _socketId + "]: "; }
|
|
|
|
|
2004-04-08 04:41:54 +00:00
|
|
|
//--------------------------------------------------
|
2004-05-07 01:32:48 +00:00
|
|
|
private class I2PInputStream extends InputStream {
|
2004-04-08 04:41:54 +00:00
|
|
|
|
2004-04-10 11:50:11 +00:00
|
|
|
private ByteCollector bc = new ByteCollector();
|
2004-08-01 18:34:02 +00:00
|
|
|
private boolean inStreamClosed = false;
|
2004-04-10 11:50:11 +00:00
|
|
|
|
2004-04-21 17:56:16 +00:00
|
|
|
private long readTimeout = -1;
|
|
|
|
|
|
|
|
public long getReadTimeout() {
|
|
|
|
return readTimeout;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setReadTimeout(long ms) {
|
|
|
|
readTimeout = ms;
|
|
|
|
}
|
|
|
|
|
2004-04-10 11:50:11 +00:00
|
|
|
public int read() throws IOException {
|
|
|
|
byte[] b = new byte[1];
|
|
|
|
int res = read(b);
|
|
|
|
if (res == 1) return b[0] & 0xff;
|
|
|
|
if (res == -1) return -1;
|
|
|
|
throw new RuntimeException("Incorrect read() result");
|
|
|
|
}
|
|
|
|
|
2004-06-28 13:21:18 +00:00
|
|
|
public int read(byte[] b, int off, int len) throws IOException {
|
2004-05-19 15:14:30 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2004-06-28 13:21:18 +00:00
|
|
|
_log.debug(getPrefix() + "Read called for " + len + " bytes (avail=" + bc.getCurrentSize() + "): " + this.hashCode());
|
2004-04-10 11:50:11 +00:00
|
|
|
if (len == 0) return 0;
|
2004-04-21 17:56:16 +00:00
|
|
|
long dieAfter = System.currentTimeMillis() + readTimeout;
|
2004-06-28 13:21:18 +00:00
|
|
|
byte[] read = null;
|
|
|
|
synchronized (bc) {
|
|
|
|
read = bc.startToByteArray(len);
|
2004-08-01 18:34:02 +00:00
|
|
|
bc.notifyAll();
|
2004-06-28 13:21:18 +00:00
|
|
|
}
|
2004-04-21 17:56:16 +00:00
|
|
|
boolean timedOut = false;
|
|
|
|
|
2004-04-10 11:50:11 +00:00
|
|
|
while (read.length == 0) {
|
|
|
|
synchronized (flagLock) {
|
|
|
|
if (closed) {
|
2004-05-19 15:14:30 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug(getPrefix() + "Closed is set after reading " + _bytesRead + " and writing " + _bytesWritten + ", so closing stream: " + hashCode());
|
2004-04-10 11:50:11 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
try {
|
2004-06-28 13:21:18 +00:00
|
|
|
synchronized (I2PSocketImpl.I2PInputStream.this) {
|
|
|
|
if (readTimeout >= 0) {
|
|
|
|
wait(readTimeout);
|
|
|
|
} else {
|
|
|
|
wait();
|
|
|
|
}
|
2004-04-21 17:56:16 +00:00
|
|
|
}
|
|
|
|
} catch (InterruptedException ex) {}
|
|
|
|
|
|
|
|
if ((readTimeout >= 0)
|
|
|
|
&& (System.currentTimeMillis() >= dieAfter)) {
|
2004-05-19 15:14:30 +00:00
|
|
|
throw new InterruptedIOException(getPrefix() + "Timeout reading from I2PSocket (" + readTimeout + " msecs)");
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
2004-04-21 17:56:16 +00:00
|
|
|
|
2004-06-28 13:21:18 +00:00
|
|
|
synchronized (bc) {
|
|
|
|
read = bc.startToByteArray(len);
|
2004-08-01 18:34:02 +00:00
|
|
|
bc.notifyAll();
|
2004-06-28 13:21:18 +00:00
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
if (read.length > len) throw new RuntimeException("BUG");
|
|
|
|
System.arraycopy(read, 0, b, off, read.length);
|
|
|
|
|
|
|
|
if (_log.shouldLog(Log.DEBUG)) {
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.debug(getPrefix() + "Read from I2PInputStream " + hashCode() + " returned "
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
+ read.length + " bytes");
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
//if (_log.shouldLog(Log.DEBUG)) {
|
|
|
|
// _log.debug("Read from I2PInputStream " + this.hashCode()
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
// + " returned "+read.length+" bytes:\n"
|
|
|
|
// + HexDump.dump(read));
|
2004-04-10 11:50:11 +00:00
|
|
|
//}
|
|
|
|
return read.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int available() {
|
2004-07-01 15:11:34 +00:00
|
|
|
synchronized (bc) {
|
|
|
|
return bc.getCurrentSize();
|
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
|
2004-08-01 18:34:02 +00:00
|
|
|
/**
|
|
|
|
* Add the data to the queue
|
|
|
|
*
|
|
|
|
* @throws InterruptedIOException if the queue's buffer is full, the socket has
|
|
|
|
* a write timeout, and that timeout is exceeded
|
|
|
|
* @throws IOException if the connection was closed while queueing up the data
|
|
|
|
*/
|
|
|
|
public void queueData(byte[] data) throws InterruptedIOException, IOException {
|
2004-04-10 11:50:11 +00:00
|
|
|
queueData(data, 0, data.length);
|
|
|
|
}
|
|
|
|
|
2004-08-01 18:34:02 +00:00
|
|
|
/**
|
|
|
|
* Add the data to the queue
|
|
|
|
*
|
|
|
|
* @throws InterruptedIOException if the queue's buffer is full, the socket has
|
|
|
|
* a write timeout, and that timeout is exceeded
|
|
|
|
* @throws IOException if the connection was closed while queueing up the data
|
|
|
|
*/
|
|
|
|
public void queueData(byte[] data, int off, int len) throws InterruptedIOException, IOException {
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.debug(getPrefix() + "Insert " + len + " bytes into queue: " + hashCode());
|
2004-08-06 22:24:56 +00:00
|
|
|
Clock clock = I2PAppContext.getGlobalContext().clock();
|
|
|
|
long endAfter = clock.now() + _options.getWriteTimeout();
|
2004-06-28 13:21:18 +00:00
|
|
|
synchronized (bc) {
|
2004-08-01 18:34:02 +00:00
|
|
|
if (_options.getMaxBufferSize() > 0) {
|
2004-08-06 22:24:56 +00:00
|
|
|
while (bc.getCurrentSize() > _options.getMaxBufferSize()) {
|
2004-08-01 18:34:02 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
|
|
|
_log.debug("Buffer size exceeded: pending " + bc.getCurrentSize() + " limit " + _options.getMaxBufferSize());
|
2004-08-06 22:24:56 +00:00
|
|
|
if (_options.getWriteTimeout() > 0) {
|
|
|
|
long timeLeft = endAfter - clock.now();
|
|
|
|
if (timeLeft <= 0) {
|
|
|
|
long waited = _options.getWriteTimeout() - timeLeft;
|
|
|
|
throw new InterruptedIOException("Waited too long (" + waited + "ms) to write "
|
|
|
|
+ len + " with a buffer at " + bc.getCurrentSize());
|
|
|
|
}
|
2004-08-01 18:34:02 +00:00
|
|
|
}
|
|
|
|
if (inStreamClosed)
|
|
|
|
throw new IOException("Stream closed while writing");
|
2004-08-06 22:24:56 +00:00
|
|
|
if (_closedOn > 0)
|
|
|
|
throw new IOException("I2PSocket closed while writing");
|
2004-08-01 18:34:02 +00:00
|
|
|
try {
|
|
|
|
bc.wait(1000);
|
|
|
|
} catch (InterruptedException ie) {}
|
|
|
|
}
|
|
|
|
}
|
2004-06-28 13:21:18 +00:00
|
|
|
bc.append(data, off, len);
|
|
|
|
}
|
|
|
|
synchronized (I2PInputStream.this) {
|
2004-07-01 15:11:34 +00:00
|
|
|
I2PInputStream.this.notifyAll();
|
2004-06-28 13:21:18 +00:00
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
|
2004-07-01 15:11:34 +00:00
|
|
|
public void notifyClosed() {
|
2004-06-28 13:21:18 +00:00
|
|
|
synchronized (I2PInputStream.this) {
|
2004-07-01 15:11:34 +00:00
|
|
|
I2PInputStream.this.notifyAll();
|
2004-06-28 13:21:18 +00:00
|
|
|
}
|
2004-05-04 05:53:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void close() throws IOException {
|
|
|
|
super.close();
|
|
|
|
notifyClosed();
|
2004-08-01 18:34:02 +00:00
|
|
|
synchronized (bc) {
|
|
|
|
inStreamClosed = true;
|
|
|
|
bc.notifyAll();
|
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-07 01:32:48 +00:00
|
|
|
private class I2POutputStream extends OutputStream {
|
2004-04-08 04:41:54 +00:00
|
|
|
|
2004-04-10 11:50:11 +00:00
|
|
|
public I2PInputStream sendTo;
|
|
|
|
|
|
|
|
public I2POutputStream(I2PInputStream sendTo) {
|
|
|
|
this.sendTo = sendTo;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void write(int b) throws IOException {
|
|
|
|
write(new byte[] { (byte) b});
|
|
|
|
}
|
|
|
|
|
|
|
|
public void write(byte[] b, int off, int len) throws IOException {
|
2004-05-19 15:14:30 +00:00
|
|
|
_bytesWritten += len;
|
2004-04-10 11:50:11 +00:00
|
|
|
sendTo.queueData(b, off, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void close() {
|
|
|
|
sendTo.notifyClosed();
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
|
|
|
|
2004-05-04 04:44:05 +00:00
|
|
|
private static volatile long __runnerId = 0;
|
2004-05-07 01:32:48 +00:00
|
|
|
private class I2PSocketRunner extends I2PThread {
|
2004-04-08 04:41:54 +00:00
|
|
|
|
2004-04-10 11:50:11 +00:00
|
|
|
public InputStream in;
|
|
|
|
|
|
|
|
public I2PSocketRunner(InputStream in) {
|
2004-05-07 01:32:48 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.debug(getPrefix() + "Runner's input stream is: " + in.hashCode());
|
2004-04-10 11:50:11 +00:00
|
|
|
this.in = in;
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
String peer = I2PSocketImpl.this.remote.calculateHash().toBase64();
|
2004-05-19 15:14:30 +00:00
|
|
|
setName("SocketRunner " + (++__runnerId) + "/" + _socketId + " " + peer.substring(0, 4));
|
2004-04-10 11:50:11 +00:00
|
|
|
start();
|
|
|
|
}
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Pump some more data
|
|
|
|
*
|
|
|
|
* @return true if we should keep on handling, false otherwise
|
|
|
|
*/
|
|
|
|
private boolean handleNextPacket(ByteCollector bc, byte buffer[])
|
|
|
|
throws IOException, I2PSessionException {
|
|
|
|
int len = in.read(buffer);
|
|
|
|
int bcsize = bc.getCurrentSize();
|
|
|
|
if (len != -1) {
|
|
|
|
bc.append(buffer, len);
|
|
|
|
} else if (bcsize == 0) {
|
2004-05-07 04:19:43 +00:00
|
|
|
// nothing left in the buffer, and read(..) got EOF (-1).
|
|
|
|
// the bart the
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if ((bcsize < MAX_PACKET_SIZE) && (in.available() == 0)) {
|
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.debug(getPrefix() + "Runner Point d: " + hashCode());
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
Thread.sleep(PACKET_DELAY);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
_log.warn("wtf", e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((bcsize >= MAX_PACKET_SIZE) || (in.available() == 0)) {
|
|
|
|
byte[] data = bc.startToByteArray(MAX_PACKET_SIZE);
|
|
|
|
if (data.length > 0) {
|
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.debug(getPrefix() + "Message size is: " + data.length);
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
boolean sent = sendBlock(data);
|
|
|
|
if (!sent) {
|
2004-07-16 20:48:40 +00:00
|
|
|
if (_log.shouldLog(Log.WARN))
|
|
|
|
_log.warn(getPrefix() + "Error sending message to peer. Killing socket runner");
|
2004-05-19 15:14:30 +00:00
|
|
|
errorOccurred();
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2004-04-10 11:50:11 +00:00
|
|
|
|
|
|
|
public void run() {
|
|
|
|
byte[] buffer = new byte[MAX_PACKET_SIZE];
|
|
|
|
ByteCollector bc = new ByteCollector();
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
boolean keepHandling = true;
|
|
|
|
int packetsHandled = 0;
|
2004-04-10 11:50:11 +00:00
|
|
|
try {
|
2004-05-07 03:06:41 +00:00
|
|
|
// try {
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
while (keepHandling) {
|
|
|
|
keepHandling = handleNextPacket(bc, buffer);
|
|
|
|
packetsHandled++;
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
if ((bc.getCurrentSize() > 0) && (packetsHandled > 1)) {
|
2004-07-16 20:48:40 +00:00
|
|
|
if (_log.shouldLog(Log.WARN))
|
|
|
|
_log.warn(getPrefix() + "We lost some data queued up due to a network send error (input stream: "
|
|
|
|
+ in.hashCode() + "; "
|
|
|
|
+ "queue size: " + bc.getCurrentSize() + ")");
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
synchronized (flagLock) {
|
|
|
|
closed2 = true;
|
|
|
|
}
|
|
|
|
boolean sc;
|
|
|
|
synchronized (flagLock) {
|
|
|
|
sc = sendClose;
|
|
|
|
} // FIXME: Race here?
|
|
|
|
if (sc) {
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
if (_log.shouldLog(Log.INFO))
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.info(getPrefix() + "Sending close packet: (we started? " + outgoing + ") after reading " + _bytesRead + " and writing " + _bytesWritten);
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
byte[] packet = I2PSocketManager.makePacket(getMask(0x02), remoteID, new byte[0]);
|
|
|
|
boolean sent = manager.getSession().sendMessage(remote, packet);
|
2004-04-10 11:50:11 +00:00
|
|
|
if (!sent) {
|
2004-07-16 20:48:40 +00:00
|
|
|
if (_log.shouldLog(Log.WARN))
|
|
|
|
_log.warn(getPrefix() + "Error sending close packet to peer");
|
2004-05-19 15:14:30 +00:00
|
|
|
errorOccurred();
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
manager.removeSocket(I2PSocketImpl.this);
|
2004-04-21 17:56:16 +00:00
|
|
|
} catch (InterruptedIOException ex) {
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.error(getPrefix() + "BUG! read() operations should not timeout!", ex);
|
2004-04-10 11:50:11 +00:00
|
|
|
} catch (IOException ex) {
|
|
|
|
// WHOEVER removes this event on inconsistent
|
|
|
|
// state before fixing the inconsistent state (a
|
|
|
|
// reference on the socket in the socket manager
|
|
|
|
// etc.) will get hanged by me personally -- mihi
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.error(getPrefix() + "Error running - **INCONSISTENT STATE!!!**", ex);
|
2004-04-10 11:50:11 +00:00
|
|
|
} catch (I2PException ex) {
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.error(getPrefix() + "Error running - **INCONSISTENT STATE!!!**", ex);
|
2004-04-10 11:50:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean sendBlock(byte data[]) throws I2PSessionException {
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
if (_log.shouldLog(Log.DEBUG))
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.debug(getPrefix() + "TIMING: Block to send for " + I2PSocketImpl.this.hashCode());
|
2004-04-10 11:50:11 +00:00
|
|
|
if (remoteID == null) {
|
2004-05-19 15:14:30 +00:00
|
|
|
_log.error(getPrefix() + "NULL REMOTEID");
|
2004-04-10 11:50:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
byte[] packet = I2PSocketManager.makePacket(getMask(0x00), remoteID, data);
|
|
|
|
boolean sent;
|
|
|
|
synchronized (flagLock) {
|
|
|
|
if (closed2) return false;
|
|
|
|
}
|
refactored packet handling into type specific methods
removed nested synchronization (which had been causing undetected deadlocks)
made sync blocks smaller, though this may have opened holes related to
resent ACK/SYN/CLOSE packets that are delivered in a race. I'm not as
fluent in the ministreaming lib code as i should be (yet), but duck's thread
dumps were showing hundreds of threads waiting on a lock that'll never get
released (since the only way to release it would be to receive another
packet, and no more packets can be received until the lock is released, etc)
also, I2PSession is threadsafe - i can see no reason to synchronize on it
(and it was being synchronized on only part of the time?)
also, refactored the charset encoding stuff and minor log tweaking
i've been testing this for the last hour or so, on eepsites and squid (large
and small files), as well as irc, and there haven't been any glitches. but
it needs more testing before it can be released, obviously.
2004-05-03 03:34:25 +00:00
|
|
|
sent = manager.getSession().sendMessage(remote, packet);
|
2004-04-10 11:50:11 +00:00
|
|
|
return sent;
|
|
|
|
}
|
2004-04-08 04:41:54 +00:00
|
|
|
}
|
2004-05-19 15:14:30 +00:00
|
|
|
|
|
|
|
public String toString() { return "" + hashCode(); }
|
2004-04-16 03:31:13 +00:00
|
|
|
}
|