Search in sources :

Example 1 with DeliveryStatusMessage

use of net.i2p.data.i2np.DeliveryStatusMessage in project i2p.i2p by i2p.

the class HandleFloodfillDatabaseStoreMessageJob method sendAck.

private void sendAck(Hash storedKey) {
    DeliveryStatusMessage msg = new DeliveryStatusMessage(getContext());
    msg.setMessageId(_message.getReplyToken());
    // Randomize for a little protection against clock-skew fingerprinting.
    // But the "arrival" isn't used for anything, right?
    // TODO just set to 0?
    // TODO we have no session to garlic wrap this with, needs new message
    msg.setArrival(getContext().clock().now() - getContext().random().nextInt(3 * 1000));
    // may be null
    TunnelId replyTunnel = _message.getReplyTunnel();
    // A store of our own RI, only if we are not FF
    DatabaseStoreMessage msg2;
    if ((getContext().netDb().floodfillEnabled() && !getContext().router().gracefulShutdownInProgress()) || storedKey.equals(getContext().routerHash())) {
        // don't send our RI if the store was our RI (from PeerTestJob)
        msg2 = null;
    } else {
        // we aren't ff, send a go-away message
        msg2 = new DatabaseStoreMessage(getContext());
        RouterInfo me = getContext().router().getRouterInfo();
        msg2.setEntry(me);
        if (_log.shouldWarn())
            _log.warn("Got a store w/ reply token, but we aren't ff: from: " + _from + " fromHash: " + _fromHash + " msg: " + _message, new Exception());
    }
    Hash toPeer = _message.getReplyGateway();
    boolean toUs = getContext().routerHash().equals(toPeer);
    // else through an exploratory tunnel.
    if (toUs && replyTunnel != null) {
        // if we are the gateway, act as if we received it
        TunnelGatewayMessage tgm = new TunnelGatewayMessage(getContext());
        tgm.setMessage(msg);
        tgm.setTunnelId(replyTunnel);
        tgm.setMessageExpiration(msg.getMessageExpiration());
        getContext().tunnelDispatcher().dispatch(tgm);
        if (msg2 != null) {
            TunnelGatewayMessage tgm2 = new TunnelGatewayMessage(getContext());
            tgm2.setMessage(msg2);
            tgm2.setTunnelId(replyTunnel);
            tgm2.setMessageExpiration(msg.getMessageExpiration());
            getContext().tunnelDispatcher().dispatch(tgm2);
        }
    } else if (toUs || getContext().commSystem().isEstablished(toPeer)) {
        Job send = new SendMessageDirectJob(getContext(), msg, toPeer, REPLY_TIMEOUT, MESSAGE_PRIORITY);
        send.runJob();
        if (msg2 != null) {
            Job send2 = new SendMessageDirectJob(getContext(), msg2, toPeer, REPLY_TIMEOUT, MESSAGE_PRIORITY);
            send2.runJob();
        }
    } else {
        // pick tunnel with endpoint closest to toPeer
        TunnelInfo outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(toPeer);
        if (outTunnel == null) {
            if (_log.shouldLog(Log.WARN))
                _log.warn("No outbound tunnel could be found");
            return;
        }
        getContext().tunnelDispatcher().dispatchOutbound(msg, outTunnel.getSendTunnelId(0), replyTunnel, toPeer);
        if (msg2 != null)
            getContext().tunnelDispatcher().dispatchOutbound(msg2, outTunnel.getSendTunnelId(0), replyTunnel, toPeer);
    }
}
Also used : TunnelGatewayMessage(net.i2p.data.i2np.TunnelGatewayMessage) RouterInfo(net.i2p.data.router.RouterInfo) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) TunnelInfo(net.i2p.router.TunnelInfo) Hash(net.i2p.data.Hash) SendMessageDirectJob(net.i2p.router.message.SendMessageDirectJob) Job(net.i2p.router.Job) TunnelId(net.i2p.data.TunnelId) SendMessageDirectJob(net.i2p.router.message.SendMessageDirectJob) DeliveryStatusMessage(net.i2p.data.i2np.DeliveryStatusMessage)

Example 2 with DeliveryStatusMessage

use of net.i2p.data.i2np.DeliveryStatusMessage in project i2p.i2p by i2p.

the class InNetMessagePool method add.

/**
 * Add a new message to the pool.
 * If there is
 * a HandlerJobBuilder for the inbound message type, the message is loaded
 * into a job created by that builder and queued up for processing instead
 * (though if the builder doesn't create a job, it is added to the pool)
 *
 * @param messageBody non-null
 * @param fromRouter may be null
 * @param fromRouterHash may be null, calculated from fromRouter if null
 *
 * @return -1 for some types of errors but not all; 0 otherwise
 *         (was queue length, long ago)
 */
public int add(I2NPMessage messageBody, RouterIdentity fromRouter, Hash fromRouterHash) {
    long exp = messageBody.getMessageExpiration();
    if (_log.shouldLog(Log.INFO))
        _log.info("Rcvd" + " ID " + messageBody.getUniqueId() + " exp. " + new Date(exp) + " type " + messageBody.getClass().getSimpleName());
    // if (messageBody instanceof DataMessage) {
    // _context.statManager().getStatLog().addData(fromRouterHash.toBase64().substring(0,6), "udp.floodDataReceived", 1, 0);
    // return 0;
    // }
    int type = messageBody.getType();
    String invalidReason = null;
    if (type == TunnelDataMessage.MESSAGE_TYPE) {
        // the IV validator is sufficient for dup detection on tunnel messages, so
        // just validate the expiration
        invalidReason = _context.messageValidator().validateMessage(exp);
    } else {
        invalidReason = _context.messageValidator().validateMessage(messageBody.getUniqueId(), exp);
    }
    if (invalidReason != null) {
        int level = Log.WARN;
        // level = Log.INFO;
        if (_log.shouldLog(level))
            _log.log(level, "Dropping message [" + messageBody.getUniqueId() + " expiring on " + exp + "]: " + messageBody.getClass().getSimpleName() + ": " + invalidReason + ": " + messageBody);
        _context.statManager().addRateData("inNetPool.dropped", 1);
        // FIXME not necessarily a duplicate, could be expired too long ago / too far in future
        _context.statManager().addRateData("inNetPool.duplicate", 1);
        _context.messageHistory().droppedOtherMessage(messageBody, (fromRouter != null ? fromRouter.calculateHash() : fromRouterHash));
        _context.messageHistory().messageProcessingError(messageBody.getUniqueId(), messageBody.getClass().getSimpleName(), "Duplicate/expired");
        return -1;
    } else {
        if (_log.shouldLog(Log.DEBUG))
            _log.debug("Message received [" + messageBody.getUniqueId() + " expiring on " + exp + "] is NOT a duplicate or exipired");
    }
    boolean jobFound = false;
    boolean allowMatches = true;
    if (type == TunnelGatewayMessage.MESSAGE_TYPE) {
        shortCircuitTunnelGateway(messageBody);
        allowMatches = false;
    } else if (type == TunnelDataMessage.MESSAGE_TYPE) {
        shortCircuitTunnelData(messageBody, fromRouterHash);
        allowMatches = false;
    } else {
        // why don't we allow type 0? There used to be a message of type 0 long ago...
        if ((type > 0) && (type < _handlerJobBuilders.length)) {
            HandlerJobBuilder builder = _handlerJobBuilders[type];
            if (_log.shouldLog(Log.DEBUG))
                _log.debug("Add msg to the pool - builder: " + builder + " type: " + messageBody.getClass().getSimpleName());
            if (builder != null) {
                Job job = builder.createJob(messageBody, fromRouter, fromRouterHash);
                if (job != null) {
                    _context.jobQueue().addJob(job);
                    jobFound = true;
                } else {
                    // ok, we may not have *found* a job, per se, but we could have, the
                    // job may have just executed inline
                    jobFound = true;
                }
            }
        }
    }
    if (allowMatches) {
        int replies = handleReplies(messageBody);
        if (replies <= 0) {
            // not handled as a reply
            if (!jobFound) {
                // was not handled via HandlerJobBuilder
                _context.messageHistory().droppedOtherMessage(messageBody, (fromRouter != null ? fromRouter.calculateHash() : fromRouterHash));
                if (type == DeliveryStatusMessage.MESSAGE_TYPE) {
                    // Avoid logging side effect from a horrible UDP EstablishmentManager hack
                    // We could set up a separate stat for it but don't bother for now
                    long arr = ((DeliveryStatusMessage) messageBody).getArrival();
                    if (arr > 10) {
                        long timeSinceSent = _context.clock().now() - arr;
                        if (_log.shouldLog(Log.WARN))
                            _log.warn("Dropping unhandled delivery status message created " + timeSinceSent + "ms ago: " + messageBody);
                        _context.statManager().addRateData("inNetPool.droppedDeliveryStatusDelay", timeSinceSent);
                    }
                // } else if (type == TunnelCreateStatusMessage.MESSAGE_TYPE) {
                // if (_log.shouldLog(Log.INFO))
                // _log.info("Dropping slow tunnel create request response: " + messageBody);
                // _context.statManager().addRateData("inNetPool.droppedTunnelCreateStatusMessage", 1, 0);
                } else if (type == DatabaseSearchReplyMessage.MESSAGE_TYPE) {
                    if (_log.shouldLog(Log.INFO))
                        _log.info("Dropping slow db lookup response: " + messageBody);
                    _context.statManager().addRateData("inNetPool.droppedDbLookupResponseMessage", 1);
                } else if (type == DatabaseLookupMessage.MESSAGE_TYPE) {
                    if (_log.shouldLog(Log.DEBUG))
                        _log.debug("Dropping netDb lookup due to throttling");
                } else {
                    if (_log.shouldLog(Log.WARN))
                        _log.warn("Message expiring on " + messageBody.getMessageExpiration() + " was not handled by a HandlerJobBuilder - DROPPING: " + messageBody, new Exception("f00!"));
                    _context.statManager().addRateData("inNetPool.dropped", 1);
                }
            } else {
                String mtype = messageBody.getClass().getName();
                _context.messageHistory().receiveMessage(mtype, messageBody.getUniqueId(), messageBody.getMessageExpiration(), fromRouterHash, true);
                // no queue
                return 0;
            }
        }
    }
    String mtype = messageBody.getClass().getName();
    _context.messageHistory().receiveMessage(mtype, messageBody.getUniqueId(), messageBody.getMessageExpiration(), fromRouterHash, true);
    // no queue
    return 0;
}
Also used : Date(java.util.Date) DeliveryStatusMessage(net.i2p.data.i2np.DeliveryStatusMessage)

Example 3 with DeliveryStatusMessage

use of net.i2p.data.i2np.DeliveryStatusMessage in project i2p.i2p by i2p.

the class OutboundClientMessageJobHelper method buildAckClove.

/**
 *  Build a clove that sends a DeliveryStatusMessage to us.
 *  As of 0.9.12, the DSM is wrapped in a GarlicMessage.
 *  @param skm encrypt dsm with this skm non-null
 *  @return null on error
 */
private static PayloadGarlicConfig buildAckClove(RouterContext ctx, Hash from, TunnelInfo replyToTunnel, long replyToken, long expiration, SessionKeyManager skm) {
    Log log = ctx.logManager().getLog(OutboundClientMessageJobHelper.class);
    if (replyToTunnel == null) {
        if (log.shouldLog(Log.WARN))
            log.warn("Unable to send client message from " + from.toBase64() + ", as there are no inbound tunnels available");
        return null;
    }
    // tunnel id on that gateway
    TunnelId replyToTunnelId = replyToTunnel.getReceiveTunnelId(0);
    // inbound tunnel gateway
    Hash replyToTunnelRouter = replyToTunnel.getPeer(0);
    if (log.shouldLog(Log.DEBUG))
        log.debug("Ack for the data message will come back along tunnel " + replyToTunnelId + ": " + replyToTunnel);
    DeliveryInstructions ackInstructions = new DeliveryInstructions();
    ackInstructions.setDeliveryMode(DeliveryInstructions.DELIVERY_MODE_TUNNEL);
    ackInstructions.setRouter(replyToTunnelRouter);
    ackInstructions.setTunnelId(replyToTunnelId);
    // defaults
    // ackInstructions.setDelayRequested(false);
    // ackInstructions.setDelaySeconds(0);
    // ackInstructions.setEncrypted(false);
    PayloadGarlicConfig ackClove = new PayloadGarlicConfig();
    ackClove.setCertificate(Certificate.NULL_CERT);
    ackClove.setDeliveryInstructions(ackInstructions);
    ackClove.setExpiration(expiration);
    ackClove.setId(ctx.random().nextLong(I2NPMessage.MAX_ID_VALUE));
    DeliveryStatusMessage dsm = buildDSM(ctx, replyToken);
    GarlicMessage msg = wrapDSM(ctx, skm, dsm);
    if (msg == null) {
        if (log.shouldLog(Log.WARN))
            log.warn("Failed to wrap ack clove");
        return null;
    }
    ackClove.setPayload(msg);
    return ackClove;
}
Also used : DeliveryInstructions(net.i2p.data.i2np.DeliveryInstructions) Log(net.i2p.util.Log) GarlicMessage(net.i2p.data.i2np.GarlicMessage) Hash(net.i2p.data.Hash) TunnelId(net.i2p.data.TunnelId) DeliveryStatusMessage(net.i2p.data.i2np.DeliveryStatusMessage)

Example 4 with DeliveryStatusMessage

use of net.i2p.data.i2np.DeliveryStatusMessage in project i2p.i2p by i2p.

the class BuildTestMessageJob method buildAckClove.

/**
 * Build a clove that sends a DeliveryStatusMessage to us
 */
private PayloadGarlicConfig buildAckClove() {
    PayloadGarlicConfig ackClove = new PayloadGarlicConfig();
    DeliveryInstructions ackInstructions = new DeliveryInstructions();
    ackInstructions.setDeliveryMode(DeliveryInstructions.DELIVERY_MODE_ROUTER);
    // yikes!
    ackInstructions.setRouter(_replyTo);
    DeliveryStatusMessage msg = new DeliveryStatusMessage(getContext());
    msg.setArrival(getContext().clock().now());
    msg.setMessageId(_testMessageKey);
    if (_log.shouldLog(Log.DEBUG))
        _log.debug("Delivery status message key: " + _testMessageKey + " arrival: " + msg.getArrival());
    ackClove.setCertificate(new Certificate(Certificate.CERTIFICATE_TYPE_NULL, null));
    ackClove.setDeliveryInstructions(ackInstructions);
    ackClove.setExpiration(_timeoutMs + getContext().clock().now());
    ackClove.setId(getContext().random().nextLong(I2NPMessage.MAX_ID_VALUE));
    ackClove.setPayload(msg);
    ackClove.setRecipient(_target);
    return ackClove;
}
Also used : DeliveryInstructions(net.i2p.data.i2np.DeliveryInstructions) DeliveryStatusMessage(net.i2p.data.i2np.DeliveryStatusMessage) Certificate(net.i2p.data.Certificate)

Example 5 with DeliveryStatusMessage

use of net.i2p.data.i2np.DeliveryStatusMessage in project i2p.i2p by i2p.

the class EstablishmentManager method sendInboundComplete.

/**
 * dont send our info immediately, just send a small data packet, and 5-10s later,
 * if the peer isnt banlisted, *then* send them our info.  this will help kick off
 * the oldnet
 * The "oldnet" was < 0.6.1.10, it is long gone.
 * The delay really slows down the network.
 * The peer is unbanlisted and marked reachable by addRemotePeerState() which calls markReachable()
 * so the check below is fairly pointless.
 * If for some strange reason an oldnet router (NETWORK_ID == 1) does show up,
 *  it's handled in UDPTransport.messageReceived()
 * (where it will get dropped, marked unreachable and banlisted at that time).
 */
private void sendInboundComplete(PeerState peer) {
    // SimpleTimer.getInstance().addEvent(new PublishToNewInbound(peer), 10*1000);
    if (_log.shouldLog(Log.INFO))
        _log.info("Completing to the peer after IB confirm: " + peer);
    DeliveryStatusMessage dsm = new DeliveryStatusMessage(_context);
    // overloaded, sure, but future versions can check this
    dsm.setArrival(_networkID);
    // This causes huge values in the inNetPool.droppedDeliveryStatusDelay stat
    // so it needs to be caught in InNetMessagePool.
    dsm.setMessageExpiration(_context.clock().now() + DATA_MESSAGE_TIMEOUT);
    dsm.setMessageId(_context.random().nextLong(I2NPMessage.MAX_ID_VALUE));
    // sent below
    // just do this inline
    // _context.simpleTimer2().addEvent(new PublishToNewInbound(peer), 0);
    Hash hash = peer.getRemotePeer();
    if ((hash != null) && (!_context.banlist().isBanlisted(hash)) && (!_transport.isUnreachable(hash))) {
        // ok, we are fine with them, send them our latest info
        // if (_log.shouldLog(Log.INFO))
        // _log.info("Publishing to the peer after confirm plus delay (without banlist): " + peer);
        // bundle the two messages together for efficiency
        DatabaseStoreMessage dbsm = getOurInfo();
        List<I2NPMessage> msgs = new ArrayList<I2NPMessage>(2);
        msgs.add(dsm);
        msgs.add(dbsm);
        _transport.send(msgs, peer);
    } else {
        _transport.send(dsm, peer);
        // nuh uh.
        if (_log.shouldLog(Log.WARN))
            _log.warn("NOT publishing to the peer after confirm plus delay (WITH banlist): " + (hash != null ? hash.toString() : "unknown"));
    }
}
Also used : I2NPMessage(net.i2p.data.i2np.I2NPMessage) DatabaseStoreMessage(net.i2p.data.i2np.DatabaseStoreMessage) ArrayList(java.util.ArrayList) Hash(net.i2p.data.Hash) DeliveryStatusMessage(net.i2p.data.i2np.DeliveryStatusMessage)

Aggregations

DeliveryStatusMessage (net.i2p.data.i2np.DeliveryStatusMessage)7 Hash (net.i2p.data.Hash)3 TunnelId (net.i2p.data.TunnelId)2 DatabaseStoreMessage (net.i2p.data.i2np.DatabaseStoreMessage)2 DeliveryInstructions (net.i2p.data.i2np.DeliveryInstructions)2 ArrayList (java.util.ArrayList)1 Date (java.util.Date)1 Certificate (net.i2p.data.Certificate)1 GarlicMessage (net.i2p.data.i2np.GarlicMessage)1 I2NPMessage (net.i2p.data.i2np.I2NPMessage)1 TunnelGatewayMessage (net.i2p.data.i2np.TunnelGatewayMessage)1 RouterInfo (net.i2p.data.router.RouterInfo)1 Job (net.i2p.router.Job)1 OutNetMessage (net.i2p.router.OutNetMessage)1 TunnelInfo (net.i2p.router.TunnelInfo)1 SendMessageDirectJob (net.i2p.router.message.SendMessageDirectJob)1 Log (net.i2p.util.Log)1