Search in sources :

Example 6 with OutNetMessage

use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.

the class NTCPConnection method locked_close.

/**
 * @return a second connection with the same peer...
 */
private synchronized NTCPConnection locked_close(boolean allowRequeue) {
    if (_chan != null)
        try {
            _chan.close();
        } catch (IOException ioe) {
        }
    if (_conKey != null)
        _conKey.cancel();
    _establishState = EstablishState.FAILED;
    NTCPConnection old = _transport.removeCon(this);
    _transport.getReader().connectionClosed(this);
    _transport.getWriter().connectionClosed(this);
    for (FIFOBandwidthLimiter.Request req : _bwInRequests) {
        req.abort();
    // we would like to return read ByteBuffers via EventPumper.releaseBuf(),
    // but we can't risk releasing it twice
    }
    _bwInRequests.clear();
    for (FIFOBandwidthLimiter.Request req : _bwOutRequests) {
        req.abort();
    }
    _bwOutRequests.clear();
    _writeBufs.clear();
    ByteBuffer bb;
    while ((bb = _readBufs.poll()) != null) {
        EventPumper.releaseBuf(bb);
    }
    List<OutNetMessage> pending = new ArrayList<OutNetMessage>();
    // _outbound.drainAllTo(pending);
    _outbound.drainTo(pending);
    for (OutNetMessage msg : pending) _transport.afterSend(msg, false, allowRequeue, msg.getLifetime());
    OutNetMessage msg = getCurrentOutbound();
    if (msg != null)
        _transport.afterSend(msg, false, allowRequeue, msg.getLifetime());
    return old;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) FIFOBandwidthLimiter(net.i2p.router.transport.FIFOBandwidthLimiter) ArrayList(java.util.ArrayList) IOException(java.io.IOException) Request(net.i2p.router.transport.FIFOBandwidthLimiter.Request) ByteBuffer(java.nio.ByteBuffer)

Example 7 with OutNetMessage

use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.

the class BuildHandler method handleReq.

/**
 * If we are dropping lots of requests before even trying to handle them,
 * I suppose you could call us "overloaded"
 */
/**
 ** unused, see handleReq() below
 *    private final static int MAX_PROACTIVE_DROPS = 240;
 *
 *    private int countProactiveDrops() {
 *        int dropped = 0;
 *        dropped += countEvents("tunnel.dropLoadProactive", 60*1000);
 *        dropped += countEvents("tunnel.dropLoad", 60*1000);
 *        dropped += countEvents("tunnel.dropLoadBacklog", 60*1000);
 *        dropped += countEvents("tunnel.dropLoadDelay", 60*1000);
 *        return dropped;
 *    }
 *
 *    private int countEvents(String stat, long period) {
 *        RateStat rs = _context.statManager().getRate(stat);
 *        if (rs != null) {
 *            Rate r = rs.getRate(period);
 *            if (r != null)
 *                return (int)r.getCurrentEventCount();
 *        }
 *        return 0;
 *    }
 ***
 */
/**
 *  Actually process the request and send the reply.
 *
 *  Todo: Replies are not subject to RED for bandwidth reasons,
 *  and the bandwidth is not credited to any tunnel.
 *  If we did credit the reply to the tunnel, it would
 *  prevent the classification of the tunnel as 'inactive' on tunnels.jsp.
 */
private void handleReq(RouterInfo nextPeerInfo, BuildMessageState state, BuildRequestRecord req, Hash nextPeer) {
    long ourId = req.readReceiveTunnelId();
    long nextId = req.readNextTunnelId();
    boolean isInGW = req.readIsInboundGateway();
    boolean isOutEnd = req.readIsOutboundEndpoint();
    Hash from = state.fromHash;
    if (from == null && state.from != null)
        from = state.from.calculateHash();
    if (isInGW && isOutEnd) {
        _context.statManager().addRateData("tunnel.rejectHostile", 1);
        _log.error("Dropping build request, IBGW+OBEP: " + req);
        if (from != null)
            _context.commSystem().mayDisconnect(from);
        return;
    }
    if (ourId <= 0 || ourId > TunnelId.MAX_ID_VALUE || nextId <= 0 || nextId > TunnelId.MAX_ID_VALUE) {
        _context.statManager().addRateData("tunnel.rejectHostile", 1);
        if (_log.shouldWarn())
            _log.warn("Dropping build request, bad tunnel ID: " + req);
        if (from != null)
            _context.commSystem().mayDisconnect(from);
        return;
    }
    // Loop checks
    if ((!isOutEnd) && _context.routerHash().equals(nextPeer)) {
        _context.statManager().addRateData("tunnel.rejectHostile", 1);
        // old i2pd
        if (_log.shouldWarn())
            _log.warn("Dropping build request, we are the next hop: " + req);
        if (from != null)
            _context.commSystem().mayDisconnect(from);
        return;
    }
    if (!isInGW) {
        // but if not, something is seriously wrong here.
        if (from == null || _context.routerHash().equals(from)) {
            _context.statManager().addRateData("tunnel.rejectHostile", 1);
            if (_log.shouldWarn())
                _log.warn("Dropping build request, we are the previous hop: " + req);
            return;
        }
    }
    if ((!isOutEnd) && (!isInGW)) {
        // A-B-C-A is not preventable
        if (nextPeer.equals(from)) {
            // i2pd does this
            _context.statManager().addRateData("tunnel.rejectHostile", 1);
            if (_log.shouldLog(Log.WARN))
                _log.warn("Dropping build request with the same previous and next hop: " + req);
            _context.commSystem().mayDisconnect(from);
            return;
        }
    }
    // time is in hours, rounded down.
    // tunnel-alt-creation.html specifies that this is enforced +/- 1 hour but it was not.
    // As of 0.9.16, allow + 5 minutes to - 65 minutes.
    long time = req.readRequestTime();
    long now = (_context.clock().now() / (60l * 60l * 1000l)) * (60 * 60 * 1000);
    long timeDiff = now - time;
    if (timeDiff > MAX_REQUEST_AGE) {
        _context.statManager().addRateData("tunnel.rejectTooOld", 1);
        if (_log.shouldLog(Log.WARN))
            _log.warn("Dropping build request too old... replay attack? " + DataHelper.formatDuration(timeDiff) + ": " + req);
        if (from != null)
            _context.commSystem().mayDisconnect(from);
        return;
    }
    if (timeDiff < 0 - MAX_REQUEST_FUTURE) {
        _context.statManager().addRateData("tunnel.rejectFuture", 1);
        if (_log.shouldLog(Log.WARN))
            _log.warn("Dropping build request too far in future " + DataHelper.formatDuration(0 - timeDiff) + ": " + req);
        if (from != null)
            _context.commSystem().mayDisconnect(from);
        return;
    }
    int response;
    if (_context.router().isHidden()) {
        _context.throttle().setTunnelStatus(_x("Rejecting tunnels: Hidden mode"));
        response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
    } else {
        response = _context.throttle().acceptTunnelRequest();
    }
    // This only checked OUR tunnels, so the log message was wrong.
    // Now checked by TunnelDispatcher.joinXXX()
    // and returned as success value, checked below.
    // if (_context.tunnelManager().getTunnelInfo(new TunnelId(ourId)) != null) {
    // if (_log.shouldLog(Log.ERROR))
    // _log.error("Already participating in a tunnel with the given Id (" + ourId + "), so gotta reject");
    // if (response == 0)
    // response = TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT;
    // }
    // if ( (response == 0) && (_context.random().nextInt(50) <= 1) )
    // response = TunnelHistory.TUNNEL_REJECT_PROBABALISTIC_REJECT;
    long recvDelay = _context.clock().now() - state.recvTime;
    if (response == 0) {
        // unused
        // int proactiveDrops = countProactiveDrops();
        float pDrop = ((float) recvDelay) / (float) (BuildRequestor.REQUEST_TIMEOUT * 3);
        pDrop = (float) Math.pow(pDrop, 16);
        if (_context.random().nextFloat() < pDrop) {
            // || (proactiveDrops > MAX_PROACTIVE_DROPS) ) ) {
            _context.statManager().addRateData("tunnel.rejectOverloaded", recvDelay);
            _context.throttle().setTunnelStatus(_x("Rejecting tunnels: Request overload"));
            // if (true || (proactiveDrops < MAX_PROACTIVE_DROPS*2))
            response = TunnelHistory.TUNNEL_REJECT_TRANSIENT_OVERLOAD;
        // else
        // response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
        } else {
            _context.statManager().addRateData("tunnel.acceptLoad", recvDelay);
        }
    }
    /*
         * Being a IBGW or OBEP generally leads to more connections, so if we are
         * approaching our connection limit (i.e. !haveCapacity()),
         * reject this request.
         *
         * Don't do this for class N or O, under the assumption that they are already talking
         * to most of the routers, so there's no reason to reject. This may drive them
         * to their conn. limits, but it's hopefully a temporary solution to the
         * tunnel build congestion. As the net grows this will have to be revisited.
         */
    RouterInfo ri = _context.router().getRouterInfo();
    if (response == 0) {
        if (ri == null) {
            // ?? We should always have a RI
            response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
        } else {
            char bw = ri.getBandwidthTier().charAt(0);
            if (bw != 'O' && bw != 'N' && bw != 'P' && bw != 'X' && ((isInGW && !_context.commSystem().haveInboundCapacity(87)) || (isOutEnd && !_context.commSystem().haveOutboundCapacity(87)))) {
                _context.statManager().addRateData("tunnel.rejectConnLimits", 1);
                _context.throttle().setTunnelStatus(_x("Rejecting tunnels: Connection limit"));
                response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
            }
        }
    }
    // We may need another counter above for requests.
    if (response == 0 && !isInGW) {
        if (from != null && _throttler.shouldThrottle(from)) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Rejecting tunnel (hop throttle), previous hop: " + from + ": " + req);
            // no setTunnelStatus() indication
            _context.statManager().addRateData("tunnel.rejectHopThrottle", 1);
            response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
        }
    }
    if (response == 0 && (!isOutEnd) && _throttler.shouldThrottle(nextPeer)) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Rejecting tunnel (hop throttle), next hop: " + req);
        _context.statManager().addRateData("tunnel.rejectHopThrottle", 1);
        // no setTunnelStatus() indication
        response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
    }
    HopConfig cfg = null;
    if (response == 0) {
        cfg = new HopConfig();
        cfg.setCreation(_context.clock().now());
        cfg.setExpiration(_context.clock().now() + 10 * 60 * 1000);
        cfg.setIVKey(req.readIVKey());
        cfg.setLayerKey(req.readLayerKey());
        if (isInGW) {
        // default
        // cfg.setReceiveFrom(null);
        } else {
            if (from != null) {
                cfg.setReceiveFrom(from);
            } else {
                // b0rk
                return;
            }
        }
        cfg.setReceiveTunnelId(DataHelper.toLong(4, ourId));
        if (isOutEnd) {
        // default
        // cfg.setSendTo(null);
        // cfg.setSendTunnelId(null);
        } else {
            cfg.setSendTo(nextPeer);
            cfg.setSendTunnelId(DataHelper.toLong(4, nextId));
        }
        // now "actually" join
        boolean success;
        if (isOutEnd)
            success = _context.tunnelDispatcher().joinOutboundEndpoint(cfg);
        else if (isInGW)
            success = _context.tunnelDispatcher().joinInboundGateway(cfg);
        else
            success = _context.tunnelDispatcher().joinParticipant(cfg);
        if (success) {
            if (_log.shouldLog(Log.DEBUG))
                _log.debug("Joining: " + req);
        } else {
            // Dup Tunnel ID. This can definitely happen (birthday paradox).
            // Probability in 11 minutes (per hop type):
            // 0.1% for 2900 tunnels; 1% for 9300 tunnels
            response = TunnelHistory.TUNNEL_REJECT_BANDWIDTH;
            _context.statManager().addRateData("tunnel.rejectDupID", 1);
            if (_log.shouldLog(Log.WARN))
                _log.warn("DUP ID failure: " + req);
        }
    }
    if (response != 0) {
        _context.statManager().addRateData("tunnel.reject." + response, 1);
        _context.messageHistory().tunnelRejected(from, new TunnelId(ourId), nextPeer, // (isOutEnd ? "outbound endpoint" : isInGW ? "inbound gw" : "participant"));
        Integer.toString(response));
        if (from != null)
            _context.commSystem().mayDisconnect(from);
        // 81% = between 75% control measures in Transports and 87% rejection above
        if ((!_context.routerHash().equals(nextPeer)) && (!_context.commSystem().haveOutboundCapacity(81)) && (!_context.commSystem().isEstablished(nextPeer))) {
            _context.statManager().addRateData("tunnel.dropConnLimits", 1);
            if (_log.shouldLog(Log.WARN))
                _log.warn("Not sending rejection due to conn limits: " + req);
            return;
        }
    } else if (isInGW && from != null) {
        // we're the start of the tunnel, no use staying connected
        _context.commSystem().mayDisconnect(from);
    }
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Responding to " + state.msg.getUniqueId() + " after " + recvDelay + " with " + response + " from " + (from != null ? from : "tunnel") + ": " + req);
    EncryptedBuildRecord reply = BuildResponseRecord.create(_context, response, req.readReplyKey(), req.readReplyIV(), state.msg.getUniqueId());
    int records = state.msg.getRecordCount();
    int ourSlot = -1;
    for (int j = 0; j < records; j++) {
        if (state.msg.getRecord(j) == null) {
            ourSlot = j;
            state.msg.setRecord(j, reply);
            // + ": " + Base64.encode(reply));
            break;
        }
    }
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Read slot " + ourSlot + " containing: " + req + " accepted? " + response + " recvDelay " + recvDelay + " replyMessage " + req.readReplyMessageId());
    // now actually send the response
    long expires = _context.clock().now() + NEXT_HOP_SEND_TIMEOUT;
    if (!isOutEnd) {
        state.msg.setUniqueId(req.readReplyMessageId());
        state.msg.setMessageExpiration(expires);
        OutNetMessage msg = new OutNetMessage(_context, state.msg, expires, PRIORITY, nextPeerInfo);
        if (response == 0)
            msg.setOnFailedSendJob(new TunnelBuildNextHopFailJob(_context, cfg));
        _context.outNetMessagePool().add(msg);
    } else {
        // We are the OBEP.
        // send it to the reply tunnel on the reply peer within a new TunnelBuildReplyMessage
        // (enough layers jrandom?)
        TunnelBuildReplyMessage replyMsg;
        if (records == TunnelBuildMessage.MAX_RECORD_COUNT)
            replyMsg = new TunnelBuildReplyMessage(_context);
        else
            replyMsg = new VariableTunnelBuildReplyMessage(_context, records);
        for (int i = 0; i < records; i++) replyMsg.setRecord(i, state.msg.getRecord(i));
        replyMsg.setUniqueId(req.readReplyMessageId());
        replyMsg.setMessageExpiration(expires);
        TunnelGatewayMessage m = new TunnelGatewayMessage(_context);
        m.setMessage(replyMsg);
        m.setMessageExpiration(expires);
        m.setTunnelId(new TunnelId(nextId));
        if (_context.routerHash().equals(nextPeer)) {
            // ok, we are the gateway, so inject it
            if (_log.shouldLog(Log.DEBUG))
                _log.debug("We are the reply gateway for " + nextId + " when replying to replyMessage " + req);
            _context.tunnelDispatcher().dispatch(m);
        } else {
            // ok, the gateway is some other peer, shove 'er across
            OutNetMessage outMsg = new OutNetMessage(_context, m, expires, PRIORITY, nextPeerInfo);
            if (response == 0)
                outMsg.setOnFailedSendJob(new TunnelBuildNextHopFailJob(_context, cfg));
            _context.outNetMessagePool().add(outMsg);
        }
    }
}
Also used : EncryptedBuildRecord(net.i2p.data.i2np.EncryptedBuildRecord) TunnelGatewayMessage(net.i2p.data.i2np.TunnelGatewayMessage) RouterInfo(net.i2p.data.router.RouterInfo) HopConfig(net.i2p.router.tunnel.HopConfig) Hash(net.i2p.data.Hash) TunnelId(net.i2p.data.TunnelId) VariableTunnelBuildReplyMessage(net.i2p.data.i2np.VariableTunnelBuildReplyMessage) TunnelBuildReplyMessage(net.i2p.data.i2np.TunnelBuildReplyMessage) VariableTunnelBuildReplyMessage(net.i2p.data.i2np.VariableTunnelBuildReplyMessage) OutNetMessage(net.i2p.router.OutNetMessage)

Example 8 with OutNetMessage

use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.

the class BuildRequestor method request.

/**
 *  Send out a build request message.
 *
 *  @param cfg ReplyMessageId must be set
 *  @return success
 */
public static boolean request(RouterContext ctx, TunnelPool pool, PooledTunnelCreatorConfig cfg, BuildExecutor exec) {
    // new style crypto fills in all the blanks, while the old style waits for replies to fill in the next hop, etc
    prepare(ctx, cfg);
    if (cfg.getLength() <= 1) {
        buildZeroHop(ctx, pool, cfg, exec);
        return true;
    }
    Log log = ctx.logManager().getLog(BuildRequestor.class);
    cfg.setTunnelPool(pool);
    TunnelInfo pairedTunnel = null;
    Hash farEnd = cfg.getFarEnd();
    TunnelManagerFacade mgr = ctx.tunnelManager();
    boolean isInbound = pool.getSettings().isInbound();
    if (pool.getSettings().isExploratory() || !usePairedTunnels(ctx)) {
        if (isInbound)
            pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd);
        else
            pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd);
    } else {
        // building a client tunnel
        if (isInbound)
            pairedTunnel = mgr.selectOutboundTunnel(pool.getSettings().getDestination(), farEnd);
        else
            pairedTunnel = mgr.selectInboundTunnel(pool.getSettings().getDestination(), farEnd);
        if (pairedTunnel == null) {
            if (isInbound) {
                // random more reliable than closest ??
                // pairedTunnel = mgr.selectOutboundExploratoryTunnel(farEnd);
                pairedTunnel = mgr.selectOutboundTunnel();
                if (pairedTunnel != null && pairedTunnel.getLength() <= 1 && mgr.getOutboundSettings().getLength() > 0 && mgr.getOutboundSettings().getLength() + mgr.getOutboundSettings().getLengthVariance() > 0) {
                    // don't build using a zero-hop expl.,
                    // as it is both very bad for anonomyity,
                    // and it takes a build slot away from exploratory
                    pairedTunnel = null;
                }
            } else {
                // random more reliable than closest ??
                // pairedTunnel = mgr.selectInboundExploratoryTunnel(farEnd);
                pairedTunnel = mgr.selectInboundTunnel();
                if (pairedTunnel != null && pairedTunnel.getLength() <= 1 && mgr.getInboundSettings().getLength() > 0 && mgr.getInboundSettings().getLength() + mgr.getInboundSettings().getLengthVariance() > 0) {
                    // ditto
                    pairedTunnel = null;
                }
            }
            if (pairedTunnel != null && log.shouldLog(Log.INFO))
                log.info("Couldn't find a paired tunnel for " + cfg + ", using exploratory tunnel");
        }
    }
    if (pairedTunnel == null) {
        if (log.shouldLog(Log.WARN))
            log.warn("Tunnel build failed, as we couldn't find a paired tunnel for " + cfg);
        exec.buildComplete(cfg, pool);
        // Not even an exploratory tunnel? We are in big trouble.
        // Let's not spin through here too fast.
        // But don't let a client tunnel waiting for exploratories slow things down too much,
        // as there may be other tunnel pools who can build
        int ms = pool.getSettings().isExploratory() ? 250 : 25;
        try {
            Thread.sleep(ms);
        } catch (InterruptedException ie) {
        }
        return false;
    }
    // long beforeCreate = System.currentTimeMillis();
    TunnelBuildMessage msg = createTunnelBuildMessage(ctx, pool, cfg, pairedTunnel, exec);
    // long createTime = System.currentTimeMillis()-beforeCreate;
    if (msg == null) {
        if (log.shouldLog(Log.WARN))
            log.warn("Tunnel build failed, as we couldn't create the tunnel build message for " + cfg);
        exec.buildComplete(cfg, pool);
        return false;
    }
    // long beforeDispatch = System.currentTimeMillis();
    if (cfg.isInbound()) {
        if (log.shouldLog(Log.INFO))
            log.info("Sending the tunnel build request " + msg.getUniqueId() + " out the tunnel " + pairedTunnel + " to " + cfg.getPeer(0) + " for " + cfg + " waiting for the reply of " + cfg.getReplyMessageId());
        // send it out a tunnel targetting the first hop
        // TODO - would be nice to have a TunnelBuildFirstHopFailJob queued if the
        // pairedTunnel is zero-hop, but no way to do that?
        ctx.tunnelDispatcher().dispatchOutbound(msg, pairedTunnel.getSendTunnelId(0), cfg.getPeer(0));
    } else {
        if (log.shouldLog(Log.INFO))
            log.info("Sending the tunnel build request directly to " + cfg.getPeer(1) + " for " + cfg + " waiting for the reply of " + cfg.getReplyMessageId() + " with msgId=" + msg.getUniqueId());
        // send it directly to the first hop
        // Add some fuzz to the TBM expiration to make it harder to guess how many hops
        // or placement in the tunnel
        msg.setMessageExpiration(ctx.clock().now() + BUILD_MSG_TIMEOUT + ctx.random().nextLong(20 * 1000));
        // We set the OutNetMessage expiration much shorter, so that the
        // TunnelBuildFirstHopFailJob fires before the 13s build expiration.
        RouterInfo peer = ctx.netDb().lookupRouterInfoLocally(cfg.getPeer(1));
        if (peer == null) {
            if (log.shouldLog(Log.WARN))
                log.warn("Could not find the next hop to send the outbound request to: " + cfg);
            exec.buildComplete(cfg, pool);
            return false;
        }
        OutNetMessage outMsg = new OutNetMessage(ctx, msg, ctx.clock().now() + FIRST_HOP_TIMEOUT, PRIORITY, peer);
        outMsg.setOnFailedSendJob(new TunnelBuildFirstHopFailJob(ctx, pool, cfg, exec));
        ctx.outNetMessagePool().add(outMsg);
    }
    // + "ms and dispatched in " + (System.currentTimeMillis()-beforeDispatch));
    return true;
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) Log(net.i2p.util.Log) RouterInfo(net.i2p.data.router.RouterInfo) VariableTunnelBuildMessage(net.i2p.data.i2np.VariableTunnelBuildMessage) TunnelBuildMessage(net.i2p.data.i2np.TunnelBuildMessage) TunnelInfo(net.i2p.router.TunnelInfo) Hash(net.i2p.data.Hash) TunnelManagerFacade(net.i2p.router.TunnelManagerFacade)

Example 9 with OutNetMessage

use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.

the class FloodfillNetworkDatabaseFacade method flood.

/**
 *  Send to a subset of all floodfill peers.
 *  We do this to implement Kademlia within the floodfills, i.e.
 *  we flood to those closest to the key.
 */
public void flood(DatabaseEntry ds) {
    Hash key = ds.getHash();
    RouterKeyGenerator gen = _context.routerKeyGenerator();
    Hash rkey = gen.getRoutingKey(key);
    FloodfillPeerSelector sel = (FloodfillPeerSelector) getPeerSelector();
    List<Hash> peers = sel.selectFloodfillParticipants(rkey, MAX_TO_FLOOD, getKBuckets());
    // todo key cert skip?
    long until = gen.getTimeTillMidnight();
    if (until < NEXT_RKEY_LS_ADVANCE_TIME || (ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO && until < NEXT_RKEY_RI_ADVANCE_TIME)) {
        // to avoid lookup faulures after midnight, also flood to some closest to the
        // next routing key for a period of time before midnight.
        Hash nkey = gen.getNextRoutingKey(key);
        List<Hash> nextPeers = sel.selectFloodfillParticipants(nkey, NEXT_FLOOD_QTY, getKBuckets());
        int i = 0;
        for (Hash h : nextPeers) {
            // But other implementations may not...
            if (h.equals(key))
                continue;
            // todo key cert skip?
            if (!peers.contains(h)) {
                peers.add(h);
                i++;
            }
        }
        if (i > 0 && _log.shouldLog(Log.INFO))
            _log.info("Flooding the entry for " + key + " to " + i + " more, just before midnight");
    }
    int flooded = 0;
    for (int i = 0; i < peers.size(); i++) {
        Hash peer = peers.get(i);
        RouterInfo target = lookupRouterInfoLocally(peer);
        if ((target == null) || (_context.banlist().isBanlisted(peer)))
            continue;
        // But other implementations may not...
        if (ds.getType() == DatabaseEntry.KEY_TYPE_ROUTERINFO && peer.equals(key))
            continue;
        if (peer.equals(_context.routerHash()))
            continue;
        DatabaseStoreMessage msg = new DatabaseStoreMessage(_context);
        msg.setEntry(ds);
        OutNetMessage m = new OutNetMessage(_context, msg, _context.clock().now() + FLOOD_TIMEOUT, FLOOD_PRIORITY, target);
        Job floodFail = new FloodFailedJob(_context, peer);
        m.setOnFailedSendJob(floodFail);
        // we want to give credit on success, even if we aren't sure,
        // because otherwise no use noting failure
        Job floodGood = new FloodSuccessJob(_context, peer);
        m.setOnSendJob(floodGood);
        _context.commSystem().processMessage(m);
        flooded++;
        if (_log.shouldLog(Log.INFO))
            _log.info("Flooding the entry for " + key.toBase64() + " to " + peer.toBase64());
    }
    if (_log.shouldLog(Log.INFO))
        _log.info("Flooded the data to " + flooded + " of " + peers.size() + " peers");
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) RouterInfo(net.i2p.data.router.RouterInfo) RouterKeyGenerator(net.i2p.data.router.RouterKeyGenerator) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) Hash(net.i2p.data.Hash) Job(net.i2p.router.Job)

Example 10 with OutNetMessage

use of net.i2p.router.OutNetMessage in project i2p.i2p by i2p.

the class OutboundMessageRegistry method registerPending.

/**
 *  @param allowEmpty is msg.getMessage() allowed to be null?
 */
@SuppressWarnings("unchecked")
private void registerPending(OutNetMessage msg, boolean allowEmpty) {
    if ((!allowEmpty) && (msg.getMessage() == null))
        throw new IllegalArgumentException("OutNetMessage doesn't contain an I2NPMessage? Impossible?");
    MessageSelector sel = msg.getReplySelector();
    if (sel == null)
        throw new IllegalArgumentException("No reply selector? Impossible?");
    if (!_activeMessages.add(msg))
        // dont add dups
        return;
    synchronized (_selectorToMessage) {
        Object oldMsg = _selectorToMessage.put(sel, msg);
        if (oldMsg != null) {
            List<OutNetMessage> multi = null;
            if (oldMsg instanceof OutNetMessage) {
                // multi = Collections.synchronizedList(new ArrayList(4));
                multi = new ArrayList<OutNetMessage>(4);
                multi.add((OutNetMessage) oldMsg);
                multi.add(msg);
                _selectorToMessage.put(sel, multi);
            } else if (oldMsg instanceof List) {
                multi = (List<OutNetMessage>) oldMsg;
                multi.add(msg);
                _selectorToMessage.put(sel, multi);
            }
            if (_log.shouldLog(Log.WARN))
                _log.warn("a single message selector [" + sel + "] with multiple messages (" + multi + ")");
        }
    }
    synchronized (_selectors) {
        _selectors.add(sel);
    }
    _cleanupTask.scheduleExpiration(sel);
}
Also used : OutNetMessage(net.i2p.router.OutNetMessage) ArrayList(java.util.ArrayList) List(java.util.List) MessageSelector(net.i2p.router.MessageSelector)

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