concurrent
This commit is contained in:
@ -6,6 +6,7 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.client.I2PSession;
|
import net.i2p.client.I2PSession;
|
||||||
@ -29,7 +30,7 @@ public class Connection {
|
|||||||
private long _sendStreamId;
|
private long _sendStreamId;
|
||||||
private long _receiveStreamId;
|
private long _receiveStreamId;
|
||||||
private long _lastSendTime;
|
private long _lastSendTime;
|
||||||
private long _lastSendId;
|
private AtomicLong _lastSendId;
|
||||||
private boolean _resetReceived;
|
private boolean _resetReceived;
|
||||||
private boolean _resetSent;
|
private boolean _resetSent;
|
||||||
private long _resetSentOn;
|
private long _resetSentOn;
|
||||||
@ -49,7 +50,7 @@ public class Connection {
|
|||||||
private boolean _isInbound;
|
private boolean _isInbound;
|
||||||
private boolean _updatedShareOpts;
|
private boolean _updatedShareOpts;
|
||||||
/** Packet ID (Long) to PacketLocal for sent but unacked packets */
|
/** Packet ID (Long) to PacketLocal for sent but unacked packets */
|
||||||
private final Map _outboundPackets;
|
private final Map<Long, PacketLocal> _outboundPackets;
|
||||||
private PacketQueue _outboundQueue;
|
private PacketQueue _outboundQueue;
|
||||||
private ConnectionPacketHandler _handler;
|
private ConnectionPacketHandler _handler;
|
||||||
private ConnectionOptions _options;
|
private ConnectionOptions _options;
|
||||||
@ -102,7 +103,7 @@ public class Connection {
|
|||||||
_options = (opts != null ? opts : new ConnectionOptions());
|
_options = (opts != null ? opts : new ConnectionOptions());
|
||||||
_outputStream.setWriteTimeout((int)_options.getWriteTimeout());
|
_outputStream.setWriteTimeout((int)_options.getWriteTimeout());
|
||||||
_inputStream.setReadTimeout((int)_options.getReadTimeout());
|
_inputStream.setReadTimeout((int)_options.getReadTimeout());
|
||||||
_lastSendId = -1;
|
_lastSendId = new AtomicLong(-1);
|
||||||
_nextSendTime = -1;
|
_nextSendTime = -1;
|
||||||
_ackedPackets = 0;
|
_ackedPackets = 0;
|
||||||
_createdOn = _context.clock().now();
|
_createdOn = _context.clock().now();
|
||||||
@ -137,9 +138,7 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getNextOutboundPacketNum() {
|
public long getNextOutboundPacketNum() {
|
||||||
synchronized (this) {
|
return _lastSendId.incrementAndGet();
|
||||||
return ++_lastSendId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void closeReceived() {
|
void closeReceived() {
|
||||||
@ -175,7 +174,7 @@ public class Connection {
|
|||||||
return false;
|
return false;
|
||||||
started = true;
|
started = true;
|
||||||
if ( (_outboundPackets.size() >= _options.getWindowSize()) || (_activeResends > 0) ||
|
if ( (_outboundPackets.size() >= _options.getWindowSize()) || (_activeResends > 0) ||
|
||||||
(_lastSendId - _highestAckedThrough > _options.getWindowSize()) ) {
|
(_lastSendId.get() - _highestAckedThrough > _options.getWindowSize()) ) {
|
||||||
if (timeoutMs > 0) {
|
if (timeoutMs > 0) {
|
||||||
if (timeLeft <= 0) {
|
if (timeLeft <= 0) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
@ -211,10 +210,10 @@ public class Connection {
|
|||||||
void ackImmediately() {
|
void ackImmediately() {
|
||||||
PacketLocal packet = null;
|
PacketLocal packet = null;
|
||||||
synchronized (_outboundPackets) {
|
synchronized (_outboundPackets) {
|
||||||
if (_outboundPackets.size() > 0) {
|
if (!_outboundPackets.isEmpty()) {
|
||||||
// ordered, so pick the lowest to retransmit
|
// ordered, so pick the lowest to retransmit
|
||||||
Iterator iter = _outboundPackets.values().iterator();
|
Iterator<PacketLocal> iter = _outboundPackets.values().iterator();
|
||||||
packet = (PacketLocal)iter.next();
|
packet = iter.next();
|
||||||
//iter.remove();
|
//iter.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,10 +402,10 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List acked = null;
|
List<PacketLocal> acked = null;
|
||||||
synchronized (_outboundPackets) {
|
synchronized (_outboundPackets) {
|
||||||
for (Iterator iter = _outboundPackets.keySet().iterator(); iter.hasNext(); ) {
|
for (Iterator<Long> iter = _outboundPackets.keySet().iterator(); iter.hasNext(); ) {
|
||||||
Long id = (Long)iter.next();
|
Long id = iter.next();
|
||||||
if (id.longValue() <= ackThrough) {
|
if (id.longValue() <= ackThrough) {
|
||||||
boolean nacked = false;
|
boolean nacked = false;
|
||||||
if (nacks != null) {
|
if (nacks != null) {
|
||||||
@ -414,7 +413,7 @@ public class Connection {
|
|||||||
for (int i = 0; i < nacks.length; i++) {
|
for (int i = 0; i < nacks.length; i++) {
|
||||||
if (nacks[i] == id.longValue()) {
|
if (nacks[i] == id.longValue()) {
|
||||||
nacked = true;
|
nacked = true;
|
||||||
PacketLocal nackedPacket = (PacketLocal)_outboundPackets.get(id);
|
PacketLocal nackedPacket = _outboundPackets.get(id);
|
||||||
nackedPacket.incrementNACKs();
|
nackedPacket.incrementNACKs();
|
||||||
break; // NACKed
|
break; // NACKed
|
||||||
}
|
}
|
||||||
@ -423,7 +422,7 @@ public class Connection {
|
|||||||
if (!nacked) { // aka ACKed
|
if (!nacked) { // aka ACKed
|
||||||
if (acked == null)
|
if (acked == null)
|
||||||
acked = new ArrayList(1);
|
acked = new ArrayList(1);
|
||||||
PacketLocal ackedPacket = (PacketLocal)_outboundPackets.get(id);
|
PacketLocal ackedPacket = _outboundPackets.get(id);
|
||||||
ackedPacket.ackReceived();
|
ackedPacket.ackReceived();
|
||||||
acked.add(ackedPacket);
|
acked.add(ackedPacket);
|
||||||
}
|
}
|
||||||
@ -433,7 +432,7 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
if (acked != null) {
|
if (acked != null) {
|
||||||
for (int i = 0; i < acked.size(); i++) {
|
for (int i = 0; i < acked.size(); i++) {
|
||||||
PacketLocal p = (PacketLocal)acked.get(i);
|
PacketLocal p = acked.get(i);
|
||||||
_outboundPackets.remove(new Long(p.getSequenceNum()));
|
_outboundPackets.remove(new Long(p.getSequenceNum()));
|
||||||
_ackedPackets++;
|
_ackedPackets++;
|
||||||
if (p.getNumSends() > 1) {
|
if (p.getNumSends() > 1) {
|
||||||
@ -443,7 +442,7 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( (_outboundPackets.size() <= 0) && (_activeResends != 0) ) {
|
if ( (_outboundPackets.isEmpty()) && (_activeResends != 0) ) {
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
_log.info("All outbound packets acked, clearing " + _activeResends);
|
_log.info("All outbound packets acked, clearing " + _activeResends);
|
||||||
_activeResends = 0;
|
_activeResends = 0;
|
||||||
@ -570,8 +569,8 @@ public class Connection {
|
|||||||
private void killOutstandingPackets() {
|
private void killOutstandingPackets() {
|
||||||
//boolean tagsCancelled = false;
|
//boolean tagsCancelled = false;
|
||||||
synchronized (_outboundPackets) {
|
synchronized (_outboundPackets) {
|
||||||
for (Iterator iter = _outboundPackets.values().iterator(); iter.hasNext(); ) {
|
for (Iterator<PacketLocal> iter = _outboundPackets.values().iterator(); iter.hasNext(); ) {
|
||||||
PacketLocal pl = (PacketLocal)iter.next();
|
PacketLocal pl = iter.next();
|
||||||
//if ( (pl.getTagsSent() != null) && (pl.getTagsSent().size() > 0) )
|
//if ( (pl.getTagsSent() != null) && (pl.getTagsSent().size() > 0) )
|
||||||
// tagsCancelled = true;
|
// tagsCancelled = true;
|
||||||
pl.cancelled();
|
pl.cancelled();
|
||||||
@ -652,11 +651,11 @@ public class Connection {
|
|||||||
/** What was the last packet Id sent to the peer?
|
/** What was the last packet Id sent to the peer?
|
||||||
* @return The last sent packet ID
|
* @return The last sent packet ID
|
||||||
*/
|
*/
|
||||||
public long getLastSendId() { return _lastSendId; }
|
public long getLastSendId() { return _lastSendId.get(); }
|
||||||
/** Set the packet Id that was sent to a peer.
|
/** Set the packet Id that was sent to a peer.
|
||||||
* @param id The packet ID
|
* @param id The packet ID
|
||||||
*/
|
*/
|
||||||
public void setLastSendId(long id) { _lastSendId = id; }
|
public void setLastSendId(long id) { _lastSendId.set(id); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the current ConnectionOptions.
|
* Retrieve the current ConnectionOptions.
|
||||||
@ -783,7 +782,7 @@ public class Connection {
|
|||||||
if (_ackSinceCongestion) {
|
if (_ackSinceCongestion) {
|
||||||
_lastCongestionSeenAt = _options.getWindowSize();
|
_lastCongestionSeenAt = _options.getWindowSize();
|
||||||
_lastCongestionTime = _context.clock().now();
|
_lastCongestionTime = _context.clock().now();
|
||||||
_lastCongestionHighestUnacked = _lastSendId;
|
_lastCongestionHighestUnacked = _lastSendId.get();
|
||||||
_ackSinceCongestion = false;
|
_ackSinceCongestion = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1022,7 +1021,7 @@ public class Connection {
|
|||||||
}
|
}
|
||||||
if (getCloseReceivedOn() > 0)
|
if (getCloseReceivedOn() > 0)
|
||||||
buf.append(" close received ").append(DataHelper.formatDuration(_context.clock().now() - getCloseReceivedOn())).append(" ago");
|
buf.append(" close received ").append(DataHelper.formatDuration(_context.clock().now() - getCloseReceivedOn())).append(" ago");
|
||||||
buf.append(" sent: ").append(1 + _lastSendId);
|
buf.append(" sent: ").append(1 + _lastSendId.get());
|
||||||
if (_inputStream != null)
|
if (_inputStream != null)
|
||||||
buf.append(" rcvd: ").append(1 + _inputStream.getHighestBlockId() - missing);
|
buf.append(" rcvd: ").append(1 + _inputStream.getHighestBlockId() - missing);
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package net.i2p.client.streaming;
|
package net.i2p.client.streaming;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.I2PException;
|
import net.i2p.I2PException;
|
||||||
@ -32,14 +32,13 @@ public class ConnectionManager {
|
|||||||
private ConnectionPacketHandler _conPacketHandler;
|
private ConnectionPacketHandler _conPacketHandler;
|
||||||
private TCBShare _tcbShare;
|
private TCBShare _tcbShare;
|
||||||
/** Inbound stream ID (Long) to Connection map */
|
/** Inbound stream ID (Long) to Connection map */
|
||||||
private Map _connectionByInboundId;
|
private ConcurrentHashMap<Long, Connection> _connectionByInboundId;
|
||||||
/** Ping ID (Long) to PingRequest */
|
/** Ping ID (Long) to PingRequest */
|
||||||
private final Map _pendingPings;
|
private final Map<Long, PingRequest> _pendingPings;
|
||||||
private boolean _allowIncoming;
|
private boolean _allowIncoming;
|
||||||
private int _maxConcurrentStreams;
|
private int _maxConcurrentStreams;
|
||||||
private ConnectionOptions _defaultOptions;
|
private ConnectionOptions _defaultOptions;
|
||||||
private volatile int _numWaiting;
|
private volatile int _numWaiting;
|
||||||
private final Object _connectionLock;
|
|
||||||
private long SoTimeout;
|
private long SoTimeout;
|
||||||
|
|
||||||
public ConnectionManager(I2PAppContext context, I2PSession session, int maxConcurrent, ConnectionOptions defaultOptions) {
|
public ConnectionManager(I2PAppContext context, I2PSession session, int maxConcurrent, ConnectionOptions defaultOptions) {
|
||||||
@ -48,9 +47,8 @@ public class ConnectionManager {
|
|||||||
_maxConcurrentStreams = maxConcurrent;
|
_maxConcurrentStreams = maxConcurrent;
|
||||||
_defaultOptions = defaultOptions;
|
_defaultOptions = defaultOptions;
|
||||||
_log = _context.logManager().getLog(ConnectionManager.class);
|
_log = _context.logManager().getLog(ConnectionManager.class);
|
||||||
_connectionByInboundId = new HashMap(32);
|
_connectionByInboundId = new ConcurrentHashMap(32);
|
||||||
_pendingPings = new HashMap(4);
|
_pendingPings = new ConcurrentHashMap(4);
|
||||||
_connectionLock = new Object();
|
|
||||||
_messageHandler = new MessageHandler(_context, this);
|
_messageHandler = new MessageHandler(_context, this);
|
||||||
_packetHandler = new PacketHandler(_context, this);
|
_packetHandler = new PacketHandler(_context, this);
|
||||||
_connectionHandler = new ConnectionHandler(_context, this);
|
_connectionHandler = new ConnectionHandler(_context, this);
|
||||||
@ -77,22 +75,17 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connection getConnectionByInboundId(long id) {
|
Connection getConnectionByInboundId(long id) {
|
||||||
synchronized (_connectionLock) {
|
return _connectionByInboundId.get(Long.valueOf(id));
|
||||||
return (Connection)_connectionByInboundId.get(new Long(id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* not guaranteed to be unique, but in case we receive more than one packet
|
* not guaranteed to be unique, but in case we receive more than one packet
|
||||||
* on an inbound connection that we havent ack'ed yet...
|
* on an inbound connection that we havent ack'ed yet...
|
||||||
*/
|
*/
|
||||||
Connection getConnectionByOutboundId(long id) {
|
Connection getConnectionByOutboundId(long id) {
|
||||||
synchronized (_connectionLock) {
|
for (Connection con : _connectionByInboundId.values()) {
|
||||||
for (Iterator iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
|
||||||
Connection con = (Connection)iter.next();
|
|
||||||
if (DataHelper.eq(con.getSendStreamId(), id))
|
if (DataHelper.eq(con.getSendStreamId(), id))
|
||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,27 +128,26 @@ public class ConnectionManager {
|
|||||||
boolean reject = false;
|
boolean reject = false;
|
||||||
int active = 0;
|
int active = 0;
|
||||||
int total = 0;
|
int total = 0;
|
||||||
synchronized (_connectionLock) {
|
|
||||||
total = _connectionByInboundId.size();
|
// just for the stat
|
||||||
for (Iterator iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
//total = _connectionByInboundId.size();
|
||||||
if ( ((Connection)iter.next()).getIsConnected() )
|
//for (Iterator iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
||||||
active++;
|
// if ( ((Connection)iter.next()).getIsConnected() )
|
||||||
}
|
// active++;
|
||||||
|
//}
|
||||||
if (locked_tooManyStreams()) {
|
if (locked_tooManyStreams()) {
|
||||||
reject = true;
|
reject = true;
|
||||||
} else {
|
} else {
|
||||||
while (true) {
|
while (true) {
|
||||||
Connection oldCon = (Connection)_connectionByInboundId.put(new Long(receiveId), con);
|
Connection oldCon = _connectionByInboundId.putIfAbsent(Long.valueOf(receiveId), con);
|
||||||
if (oldCon == null) {
|
if (oldCon == null) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
_connectionByInboundId.put(new Long(receiveId), oldCon);
|
|
||||||
// receiveId already taken, try another
|
// receiveId already taken, try another
|
||||||
receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_context.statManager().addRateData("stream.receiveActive", active, total);
|
_context.statManager().addRateData("stream.receiveActive", active, total);
|
||||||
|
|
||||||
@ -179,9 +171,7 @@ public class ConnectionManager {
|
|||||||
try {
|
try {
|
||||||
con.getPacketHandler().receivePacket(synPacket, con);
|
con.getPacketHandler().receivePacket(synPacket, con);
|
||||||
} catch (I2PException ie) {
|
} catch (I2PException ie) {
|
||||||
synchronized (_connectionLock) {
|
_connectionByInboundId.remove(Long.valueOf(receiveId));
|
||||||
_connectionByInboundId.remove(new Long(receiveId));
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,8 +205,7 @@ public class ConnectionManager {
|
|||||||
_numWaiting--;
|
_numWaiting--;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
boolean reject = false;
|
|
||||||
synchronized (_connectionLock) {
|
|
||||||
if (locked_tooManyStreams()) {
|
if (locked_tooManyStreams()) {
|
||||||
// allow a full buffer of pending/waiting streams
|
// allow a full buffer of pending/waiting streams
|
||||||
if (_numWaiting > _maxConcurrentStreams) {
|
if (_numWaiting > _maxConcurrentStreams) {
|
||||||
@ -227,27 +216,30 @@ public class ConnectionManager {
|
|||||||
_numWaiting--;
|
_numWaiting--;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// no remaining streams, lets wait a bit
|
// no remaining streams, lets wait a bit
|
||||||
try { _connectionLock.wait(remaining); } catch (InterruptedException ie) {}
|
// got rid of the lock, so just sleep (fixme?)
|
||||||
|
// try { _connectionLock.wait(remaining); } catch (InterruptedException ie) {}
|
||||||
|
try { Thread.sleep(remaining/4); } catch (InterruptedException ie) {}
|
||||||
} else {
|
} else {
|
||||||
con = new Connection(_context, this, _schedulerChooser, _outboundQueue, _conPacketHandler, opts);
|
con = new Connection(_context, this, _schedulerChooser, _outboundQueue, _conPacketHandler, opts);
|
||||||
con.setRemotePeer(peer);
|
con.setRemotePeer(peer);
|
||||||
|
|
||||||
while (_connectionByInboundId.containsKey(new Long(receiveId))) {
|
while (_connectionByInboundId.containsKey(Long.valueOf(receiveId))) {
|
||||||
receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
receiveId = _context.random().nextLong(Packet.MAX_STREAM_ID-1)+1;
|
||||||
}
|
}
|
||||||
_connectionByInboundId.put(new Long(receiveId), con);
|
_connectionByInboundId.put(Long.valueOf(receiveId), con);
|
||||||
break; // stop looping as a psuedo-wait
|
break; // stop looping as a psuedo-wait
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok we're in...
|
// ok we're in...
|
||||||
con.setReceiveStreamId(receiveId);
|
con.setReceiveStreamId(receiveId);
|
||||||
con.eventOccurred();
|
con.eventOccurred();
|
||||||
|
|
||||||
_log.debug("Connect() conDelay = " + opts.getConnectDelay());
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
|
_log.debug("Connect() conDelay = " + opts.getConnectDelay());
|
||||||
if (opts.getConnectDelay() <= 0) {
|
if (opts.getConnectDelay() <= 0) {
|
||||||
con.waitForConnect();
|
con.waitForConnect();
|
||||||
}
|
}
|
||||||
@ -258,12 +250,15 @@ public class ConnectionManager {
|
|||||||
return con;
|
return con;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doesn't need to be locked any more
|
||||||
|
* @return too many
|
||||||
|
*/
|
||||||
private boolean locked_tooManyStreams() {
|
private boolean locked_tooManyStreams() {
|
||||||
if (_maxConcurrentStreams <= 0) return false;
|
if (_maxConcurrentStreams <= 0) return false;
|
||||||
if (_connectionByInboundId.size() < _maxConcurrentStreams) return false;
|
if (_connectionByInboundId.size() < _maxConcurrentStreams) return false;
|
||||||
int active = 0;
|
int active = 0;
|
||||||
for (Iterator iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
for (Connection con : _connectionByInboundId.values()) {
|
||||||
Connection con = (Connection)iter.next();
|
|
||||||
if (con.getIsConnected())
|
if (con.getIsConnected())
|
||||||
active++;
|
active++;
|
||||||
}
|
}
|
||||||
@ -293,13 +288,10 @@ public class ConnectionManager {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public void disconnectAllHard() {
|
public void disconnectAllHard() {
|
||||||
synchronized (_connectionLock) {
|
for (Iterator<Connection> iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
||||||
for (Iterator iter = _connectionByInboundId.values().iterator(); iter.hasNext(); ) {
|
Connection con = iter.next();
|
||||||
Connection con = (Connection)iter.next();
|
con.disconnect(false, false);
|
||||||
con.disconnect(false, false);
|
iter.remove();
|
||||||
}
|
|
||||||
_connectionByInboundId.clear();
|
|
||||||
_connectionLock.notifyAll();
|
|
||||||
}
|
}
|
||||||
_tcbShare.stop();
|
_tcbShare.stop();
|
||||||
}
|
}
|
||||||
@ -310,17 +302,15 @@ public class ConnectionManager {
|
|||||||
* @param con Connection to drop.
|
* @param con Connection to drop.
|
||||||
*/
|
*/
|
||||||
public void removeConnection(Connection con) {
|
public void removeConnection(Connection con) {
|
||||||
boolean removed = false;
|
|
||||||
synchronized (_connectionLock) {
|
Object o = _connectionByInboundId.remove(Long.valueOf(con.getReceiveStreamId()));
|
||||||
Object o = _connectionByInboundId.remove(new Long(con.getReceiveStreamId()));
|
boolean removed = (o == con);
|
||||||
removed = (o == con);
|
|
||||||
if (_log.shouldLog(Log.DEBUG))
|
if (_log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Connection removed? " + removed + " remaining: "
|
_log.debug("Connection removed? " + removed + " remaining: "
|
||||||
+ _connectionByInboundId.size() + ": " + con);
|
+ _connectionByInboundId.size() + ": " + con);
|
||||||
if (!removed && _log.shouldLog(Log.DEBUG))
|
if (!removed && _log.shouldLog(Log.DEBUG))
|
||||||
_log.debug("Failed to remove " + con +"\n" + _connectionByInboundId.values());
|
_log.debug("Failed to remove " + con +"\n" + _connectionByInboundId.values());
|
||||||
_connectionLock.notifyAll();
|
|
||||||
}
|
|
||||||
if (removed) {
|
if (removed) {
|
||||||
_context.statManager().addRateData("stream.con.lifetimeMessagesSent", 1+con.getLastSendId(), con.getLifetime());
|
_context.statManager().addRateData("stream.con.lifetimeMessagesSent", 1+con.getLastSendId(), con.getLifetime());
|
||||||
MessageInputStream stream = con.getInputStream();
|
MessageInputStream stream = con.getInputStream();
|
||||||
@ -344,10 +334,8 @@ public class ConnectionManager {
|
|||||||
/** return a set of Connection objects
|
/** return a set of Connection objects
|
||||||
* @return set of Connection objects
|
* @return set of Connection objects
|
||||||
*/
|
*/
|
||||||
public Set listConnections() {
|
public Set<Connection> listConnections() {
|
||||||
synchronized (_connectionLock) {
|
|
||||||
return new HashSet(_connectionByInboundId.values());
|
return new HashSet(_connectionByInboundId.values());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** blocking */
|
/** blocking */
|
||||||
@ -368,7 +356,7 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean ping(Destination peer, long timeoutMs, boolean blocking, PingNotifier notifier) {
|
public boolean ping(Destination peer, long timeoutMs, boolean blocking, PingNotifier notifier) {
|
||||||
Long id = new Long(_context.random().nextLong(Packet.MAX_STREAM_ID-1)+1);
|
Long id = Long.valueOf(_context.random().nextLong(Packet.MAX_STREAM_ID-1)+1);
|
||||||
PacketLocal packet = new PacketLocal(_context, peer);
|
PacketLocal packet = new PacketLocal(_context, peer);
|
||||||
packet.setSendStreamId(id.longValue());
|
packet.setSendStreamId(id.longValue());
|
||||||
packet.setFlag(Packet.FLAG_ECHO);
|
packet.setFlag(Packet.FLAG_ECHO);
|
||||||
@ -381,9 +369,7 @@ public class ConnectionManager {
|
|||||||
|
|
||||||
PingRequest req = new PingRequest(peer, packet, notifier);
|
PingRequest req = new PingRequest(peer, packet, notifier);
|
||||||
|
|
||||||
synchronized (_pendingPings) {
|
_pendingPings.put(id, req);
|
||||||
_pendingPings.put(id, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
_outboundQueue.enqueue(packet);
|
_outboundQueue.enqueue(packet);
|
||||||
packet.releasePayload();
|
packet.releasePayload();
|
||||||
@ -393,10 +379,7 @@ public class ConnectionManager {
|
|||||||
if (!req.pongReceived())
|
if (!req.pongReceived())
|
||||||
try { req.wait(timeoutMs); } catch (InterruptedException ie) {}
|
try { req.wait(timeoutMs); } catch (InterruptedException ie) {}
|
||||||
}
|
}
|
||||||
|
_pendingPings.remove(id);
|
||||||
synchronized (_pendingPings) {
|
|
||||||
_pendingPings.remove(id);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
SimpleTimer.getInstance().addEvent(new PingFailed(id, notifier), timeoutMs);
|
SimpleTimer.getInstance().addEvent(new PingFailed(id, notifier), timeoutMs);
|
||||||
}
|
}
|
||||||
@ -418,13 +401,8 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void timeReached() {
|
public void timeReached() {
|
||||||
boolean removed = false;
|
PingRequest pr = _pendingPings.remove(_id);
|
||||||
synchronized (_pendingPings) {
|
if (pr != null) {
|
||||||
Object o = _pendingPings.remove(_id);
|
|
||||||
if (o != null)
|
|
||||||
removed = true;
|
|
||||||
}
|
|
||||||
if (removed) {
|
|
||||||
if (_notifier != null)
|
if (_notifier != null)
|
||||||
_notifier.pingComplete(false);
|
_notifier.pingComplete(false);
|
||||||
if (_log.shouldLog(Log.INFO))
|
if (_log.shouldLog(Log.INFO))
|
||||||
@ -433,7 +411,7 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PingRequest {
|
private static class PingRequest {
|
||||||
private boolean _ponged;
|
private boolean _ponged;
|
||||||
private Destination _peer;
|
private Destination _peer;
|
||||||
private PacketLocal _packet;
|
private PacketLocal _packet;
|
||||||
@ -445,7 +423,8 @@ public class ConnectionManager {
|
|||||||
_notifier = notifier;
|
_notifier = notifier;
|
||||||
}
|
}
|
||||||
public void pong() {
|
public void pong() {
|
||||||
_log.debug("Ping successful");
|
// static, no log
|
||||||
|
//_log.debug("Ping successful");
|
||||||
//_context.sessionKeyManager().tagsDelivered(_peer.getPublicKey(), _packet.getKeyUsed(), _packet.getTagsSent());
|
//_context.sessionKeyManager().tagsDelivered(_peer.getPublicKey(), _packet.getKeyUsed(), _packet.getTagsSent());
|
||||||
synchronized (ConnectionManager.PingRequest.this) {
|
synchronized (ConnectionManager.PingRequest.this) {
|
||||||
_ponged = true;
|
_ponged = true;
|
||||||
@ -458,10 +437,7 @@ public class ConnectionManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void receivePong(long pingId) {
|
void receivePong(long pingId) {
|
||||||
PingRequest req = null;
|
PingRequest req = _pendingPings.remove(Long.valueOf(pingId));
|
||||||
synchronized (_pendingPings) {
|
|
||||||
req = (PingRequest)_pendingPings.remove(new Long(pingId));
|
|
||||||
}
|
|
||||||
if (req != null)
|
if (req != null)
|
||||||
req.pong();
|
req.pong();
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package net.i2p.client.streaming;
|
package net.i2p.client.streaming;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.i2p.I2PAppContext;
|
import net.i2p.I2PAppContext;
|
||||||
import net.i2p.client.I2PSession;
|
import net.i2p.client.I2PSession;
|
||||||
import net.i2p.client.I2PSessionException;
|
import net.i2p.client.I2PSessionException;
|
||||||
import net.i2p.client.I2PSessionListener;
|
import net.i2p.client.I2PSessionListener;
|
||||||
import net.i2p.util.Log;
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.ConcurrentHashSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive raw information from the I2PSession and turn it into
|
* Receive raw information from the I2PSession and turn it into
|
||||||
@ -18,12 +19,12 @@ public class MessageHandler implements I2PSessionListener {
|
|||||||
private ConnectionManager _manager;
|
private ConnectionManager _manager;
|
||||||
private I2PAppContext _context;
|
private I2PAppContext _context;
|
||||||
private Log _log;
|
private Log _log;
|
||||||
private final List _listeners;
|
private final Set<I2PSocketManager.DisconnectListener> _listeners;
|
||||||
|
|
||||||
public MessageHandler(I2PAppContext ctx, ConnectionManager mgr) {
|
public MessageHandler(I2PAppContext ctx, ConnectionManager mgr) {
|
||||||
_manager = mgr;
|
_manager = mgr;
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
_listeners = new ArrayList(1);
|
_listeners = new ConcurrentHashSet(1);
|
||||||
_log = ctx.logManager().getLog(MessageHandler.class);
|
_log = ctx.logManager().getLog(MessageHandler.class);
|
||||||
_context.statManager().createRateStat("stream.packetReceiveFailure", "When do we fail to decrypt or otherwise receive a packet sent to us?", "Stream", new long[] { 60*60*1000, 24*60*60*1000 });
|
_context.statManager().createRateStat("stream.packetReceiveFailure", "When do we fail to decrypt or otherwise receive a packet sent to us?", "Stream", new long[] { 60*60*1000, 24*60*60*1000 });
|
||||||
}
|
}
|
||||||
@ -77,14 +78,10 @@ public class MessageHandler implements I2PSessionListener {
|
|||||||
_log.warn("I2PSession disconnected");
|
_log.warn("I2PSession disconnected");
|
||||||
_manager.disconnectAllHard();
|
_manager.disconnectAllHard();
|
||||||
|
|
||||||
List listeners = null;
|
for (Iterator<I2PSocketManager.DisconnectListener> iter = _listeners.iterator(); iter.hasNext(); ) {
|
||||||
synchronized (_listeners) {
|
I2PSocketManager.DisconnectListener lsnr = iter.next();
|
||||||
listeners = new ArrayList(_listeners);
|
|
||||||
_listeners.clear();
|
|
||||||
}
|
|
||||||
for (int i = 0; i < listeners.size(); i++) {
|
|
||||||
I2PSocketManager.DisconnectListener lsnr = (I2PSocketManager.DisconnectListener)listeners.get(i);
|
|
||||||
lsnr.sessionDisconnected();
|
lsnr.sessionDisconnected();
|
||||||
|
iter.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,13 +101,9 @@ public class MessageHandler implements I2PSessionListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void addDisconnectListener(I2PSocketManager.DisconnectListener lsnr) {
|
public void addDisconnectListener(I2PSocketManager.DisconnectListener lsnr) {
|
||||||
synchronized (_listeners) {
|
|
||||||
_listeners.add(lsnr);
|
_listeners.add(lsnr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public void removeDisconnectListener(I2PSocketManager.DisconnectListener lsnr) {
|
public void removeDisconnectListener(I2PSocketManager.DisconnectListener lsnr) {
|
||||||
synchronized (_listeners) {
|
|
||||||
_listeners.remove(lsnr);
|
_listeners.remove(lsnr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user