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);
}
}
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;
}
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;
}
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;
}
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"));
}
}
Aggregations