use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class OutboundMessageRegistry method getOriginalMessages.
/**
* Retrieve all messages that are waiting for the specified message. In
* addition, those matches may include instructions to either continue or not
* continue waiting for further replies - if it should continue, the matched
* message remains in the registry, but if it shouldn't continue, the matched
* message is removed from the registry.
*
* This is called only by InNetMessagePool.
*
* TODO this calls isMatch() in the selectors from inside the lock, which
* can lead to deadlocks if the selector does too much in isMatch().
* Remove the lock if possible.
*
* @param message Payload received that may be a reply to something we sent
* @return non-null List of OutNetMessage describing messages that were waiting for
* the payload
*/
@SuppressWarnings("unchecked")
public List<OutNetMessage> getOriginalMessages(I2NPMessage message) {
List<MessageSelector> matchedSelectors = null;
List<MessageSelector> removedSelectors = null;
synchronized (_selectors) {
// MessageSelector sel = iter.next();
for (int i = 0; i < _selectors.size(); i++) {
MessageSelector sel = _selectors.get(i);
boolean isMatch = sel.isMatch(message);
if (isMatch) {
if (matchedSelectors == null)
matchedSelectors = new ArrayList<MessageSelector>(1);
matchedSelectors.add(sel);
if (!sel.continueMatching()) {
if (removedSelectors == null)
removedSelectors = new ArrayList<MessageSelector>(1);
removedSelectors.add(sel);
// iter.remove();
_selectors.remove(i);
i--;
}
}
}
}
List<OutNetMessage> rv;
if (matchedSelectors != null) {
rv = new ArrayList<OutNetMessage>(matchedSelectors.size());
for (MessageSelector sel : matchedSelectors) {
boolean removed = false;
OutNetMessage msg = null;
List<OutNetMessage> msgs = null;
synchronized (_selectorToMessage) {
Object o = null;
if ((removedSelectors != null) && (removedSelectors.contains(sel))) {
o = _selectorToMessage.remove(sel);
removed = true;
} else {
o = _selectorToMessage.get(sel);
}
if (o instanceof OutNetMessage) {
msg = (OutNetMessage) o;
rv.add(msg);
} else if (o instanceof List) {
msgs = (List<OutNetMessage>) o;
rv.addAll(msgs);
}
}
if (removed) {
if (msg != null) {
_activeMessages.remove(msg);
} else if (msgs != null) {
_activeMessages.removeAll(msgs);
}
}
}
} else {
rv = Collections.emptyList();
}
return rv;
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class OutboundMessageRegistry method registerPending.
/**
* Registers a new, empty OutNetMessage, with the reply and timeout jobs specified.
* The onTimeout job is called at replySelector.getExpiration() (if no reply is received by then)
*
* @param replySelector non-null; The same selector may be used for more than one message.
* @param onReply non-null
* @param onTimeout may be null
* @return a dummy OutNetMessage where getMessage() is null. Use it to call unregisterPending() later if desired.
*/
public OutNetMessage registerPending(MessageSelector replySelector, ReplyJob onReply, Job onTimeout) {
OutNetMessage msg = new OutNetMessage(_context);
msg.setOnFailedReplyJob(onTimeout);
msg.setOnReplyJob(onReply);
msg.setReplySelector(replySelector);
registerPending(msg, true);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Registered: " + replySelector + " with reply job " + onReply + " and timeout job " + onTimeout);
return msg;
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class OutboundMessageFragments method preparePackets.
/**
* @return null if state or peer is null
*/
private List<UDPPacket> preparePackets(List<OutboundMessageState> states, PeerState peer) {
if (states == null || peer == null)
return null;
// ok, simplest possible thing is to always tack on the bitfields if
List<Long> msgIds = peer.getCurrentFullACKs();
int newFullAckCount = msgIds.size();
msgIds.addAll(peer.getCurrentResendACKs());
List<ACKBitfield> partialACKBitfields = new ArrayList<ACKBitfield>();
peer.fetchPartialACKs(partialACKBitfields);
int piggybackedPartialACK = partialACKBitfields.size();
// getCurrentFullACKs() already makes a copy, do we need to copy again?
// YES because buildPacket() now removes them (maybe)
List<Long> remaining = new ArrayList<Long>(msgIds);
// build the list of fragments to send
List<Fragment> toSend = new ArrayList<Fragment>(8);
for (OutboundMessageState state : states) {
int fragments = state.getFragmentCount();
int queued = 0;
for (int i = 0; i < fragments; i++) {
if (state.needsSending(i)) {
toSend.add(new Fragment(state, i));
queued++;
}
}
// per-state stats
if (queued > 0 && state.getPushCount() > 1) {
peer.messageRetransmitted(queued);
// _packetsRetransmitted += toSend; // lifetime for the transport
_context.statManager().addRateData("udp.peerPacketsRetransmitted", peer.getPacketsRetransmitted(), peer.getPacketsTransmitted());
_context.statManager().addRateData("udp.packetsRetransmitted", state.getLifetime(), peer.getPacketsTransmitted());
if (_log.shouldLog(Log.INFO))
_log.info("Retransmitting " + state + " to " + peer);
_context.statManager().addRateData("udp.sendVolleyTime", state.getLifetime(), queued);
}
}
if (toSend.isEmpty())
return null;
int fragmentsToSend = toSend.size();
// sort by size, biggest first
// don't bother unless more than one state (fragments are already sorted within a state)
// This puts the DeliveryStatusMessage after the DatabaseStoreMessage, don't do it for now.
// It also undoes the ordering of the priority queue in PeerState.
// if (fragmentsToSend > 1 && states.size() > 1)
// Collections.sort(toSend, new FragmentComparator());
List<Fragment> sendNext = new ArrayList<Fragment>(Math.min(toSend.size(), 4));
List<UDPPacket> rv = new ArrayList<UDPPacket>(toSend.size());
for (int i = 0; i < toSend.size(); i++) {
Fragment next = toSend.get(i);
sendNext.add(next);
OutboundMessageState state = next.state;
OutNetMessage msg = state.getMessage();
int msgType = (msg != null) ? msg.getMessageTypeId() : -1;
if (_log.shouldLog(Log.INFO))
_log.info("Building packet for " + next + " to " + peer);
int curTotalDataSize = state.fragmentSize(next.num);
// now stuff in more fragments if they fit
if (i + 1 < toSend.size()) {
int maxAvail = PacketBuilder.getMaxAdditionalFragmentSize(peer, sendNext.size(), curTotalDataSize);
for (int j = i + 1; j < toSend.size(); j++) {
next = toSend.get(j);
int nextDataSize = next.state.fragmentSize(next.num);
// if (_builder.canFitAnotherFragment(peer, sendNext.size(), curTotalDataSize, nextDataSize)) {
if (nextDataSize <= maxAvail) {
// add it
toSend.remove(j);
j--;
sendNext.add(next);
curTotalDataSize += nextDataSize;
maxAvail = PacketBuilder.getMaxAdditionalFragmentSize(peer, sendNext.size(), curTotalDataSize);
if (_log.shouldLog(Log.INFO))
_log.info("Adding in additional " + next + " to " + peer);
}
// else too big
}
}
int before = remaining.size();
UDPPacket pkt = _builder.buildPacket(sendNext, peer, remaining, newFullAckCount, partialACKBitfields);
if (pkt != null) {
if (_log.shouldLog(Log.INFO))
_log.info("Built packet with " + sendNext.size() + " fragments totalling " + curTotalDataSize + " data bytes to " + peer);
_context.statManager().addRateData("udp.sendFragmentsPerPacket", sendNext.size());
}
sendNext.clear();
if (pkt == null) {
if (_log.shouldLog(Log.WARN))
_log.info("Build packet FAIL for " + DataHelper.toString(sendNext) + " to " + peer);
continue;
}
rv.add(pkt);
int after = remaining.size();
newFullAckCount = Math.max(0, newFullAckCount - (before - after));
int piggybackedAck = 0;
if (msgIds.size() != remaining.size()) {
for (int j = 0; j < msgIds.size(); j++) {
Long id = msgIds.get(j);
if (!remaining.contains(id)) {
peer.removeACKMessage(id);
piggybackedAck++;
}
}
}
if (piggybackedAck > 0)
_context.statManager().addRateData("udp.sendPiggyback", piggybackedAck);
if (piggybackedPartialACK - partialACKBitfields.size() > 0)
_context.statManager().addRateData("udp.sendPiggybackPartial", piggybackedPartialACK - partialACKBitfields.size(), state.getLifetime());
// following for debugging and stats
pkt.setFragmentCount(sendNext.size());
// type of first fragment
pkt.setMessageType(msgType);
}
int sent = rv.size();
peer.packetsTransmitted(sent);
if (_log.shouldLog(Log.INFO))
_log.info("Sent " + fragmentsToSend + " fragments of " + states.size() + " messages in " + sent + " packets to " + peer);
return rv;
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class TimedWeightedPriorityMessageQueue method getNext.
/**
* Grab the next message out of the next queue. This only advances
* the _nextQueue var after pushing _weighting[currentQueue] messages
* or the queue is empty. This call blocks until either a message
* becomes available or the queue is shut down.
*
* @param blockUntil expiration, or -1 if indefinite
* @return message dequeued, or null if the queue was shut down
*/
public OutNetMessage getNext(long blockUntil) {
while (_alive) {
_addedSincePassBegan = false;
for (int i = 0; i < _queue.length; i++) {
int currentQueue = (_nextQueue + i) % _queue.length;
synchronized (_queue[currentQueue]) {
for (int j = 0; j < _queue[currentQueue].size(); j++) {
OutNetMessage msg = _queue[currentQueue].get(j);
Hash to = msg.getTarget().getIdentity().getHash();
if (_chokedPeers.contains(to))
continue;
// not choked, lets push it to active
_queue[currentQueue].remove(j);
long size = msg.getMessageSize();
_bytesQueued[currentQueue] -= size;
_bytesTransferred[currentQueue] += size;
_messagesFlushed[currentQueue]++;
if (_messagesFlushed[currentQueue] >= _weighting[currentQueue]) {
_messagesFlushed[currentQueue] = 0;
_nextQueue = (currentQueue + 1) % _queue.length;
}
int sz = _queue[currentQueue].size();
_context.statManager().addRateData("udp.messageQueueSize", sz, currentQueue);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Pulling a message off queue " + currentQueue + " with " + sz + " remaining");
msg.timestamp("made active with remaining queue size " + sz);
return msg;
}
// nothing waiting, or only choked peers
_messagesFlushed[currentQueue] = 0;
if (_log.shouldLog(Log.DEBUG))
_log.debug("Nothing available on queue " + currentQueue);
}
}
long remaining = blockUntil - _context.clock().now();
if ((blockUntil > 0) && (remaining < 0)) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Nonblocking, or block time has expired");
return null;
}
try {
synchronized (_nextLock) {
if (!_addedSincePassBegan && _alive) {
// wait, but it doesn't hurt to loop again.
if (_log.shouldLog(Log.DEBUG))
_log.debug("Wait for activity (up to " + remaining + "ms)");
if (blockUntil < 0)
_nextLock.wait();
else
_nextLock.wait(remaining);
}
}
} catch (InterruptedException ie) {
}
}
return null;
}
use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.
the class TunnelParticipant method send.
private void send(HopConfig config, TunnelDataMessage msg, RouterInfo ri) {
if (_context.tunnelDispatcher().shouldDropParticipatingMessage(TunnelDispatcher.Location.PARTICIPANT, TunnelDataMessage.MESSAGE_TYPE, 1024))
return;
// _config.incrementSentMessages();
_context.bandwidthLimiter().sentParticipatingMessage(1024);
long oldId = msg.getUniqueId();
long newId = _context.random().nextLong(I2NPMessage.MAX_ID_VALUE);
_context.messageHistory().wrap("TunnelDataMessage", oldId, "TunnelDataMessage", newId);
msg.setUniqueId(newId);
msg.setMessageExpiration(_context.clock().now() + 10 * 1000);
msg.setTunnelId(config.getSendTunnel());
OutNetMessage m = new OutNetMessage(_context, msg, msg.getMessageExpiration(), PRIORITY, ri);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Forward on from " + _config + ": " + msg);
_context.outNetMessagePool().add(m);
}
Aggregations