Search in sources :

Example 11 with OutNetMessage

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;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) ArrayList(java.util.ArrayList) ArrayList(java.util.ArrayList) List(java.util.List) MessageSelector(net.i2p.router.MessageSelector)

Example 12 with OutNetMessage

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;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage)

Example 13 with OutNetMessage

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;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) ArrayList(java.util.ArrayList) Fragment(net.i2p.router.transport.udp.PacketBuilder.Fragment)

Example 14 with OutNetMessage

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;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) Hash(net.i2p.data.Hash)

Example 15 with OutNetMessage

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);
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage)

Aggregations

OutNetMessage (net.i2p.router.OutNetMessage)36 ArrayList (java.util.ArrayList)9 Hash (net.i2p.data.Hash)9 RouterInfo (net.i2p.data.router.RouterInfo)9 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)5 List (java.util.List)4 RouterIdentity (net.i2p.data.router.RouterIdentity)4 I2NPMessage (net.i2p.data.i2np.I2NPMessage)3 RouterAddress (net.i2p.data.router.RouterAddress)3 MessageSelector (net.i2p.router.MessageSelector)3 IOException (java.io.IOException)2 TunnelGatewayMessage (net.i2p.data.i2np.TunnelGatewayMessage)2 Job (net.i2p.router.Job)2 TunnelInfo (net.i2p.router.TunnelInfo)2 TunnelManagerFacade (net.i2p.router.TunnelManagerFacade)2 InetAddress (java.net.InetAddress)1 ByteBuffer (java.nio.ByteBuffer)1 ServerSocketChannel (java.nio.channels.ServerSocketChannel)1 SocketChannel (java.nio.channels.SocketChannel)1 Map (java.util.Map)1