use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class MessageReceiver method readMessage.
/**
* Assemble all the fragments into an I2NP message.
* This calls state.releaseResources(), do not access state after calling this.
*
* @param buf temp buffer for convenience
* @return null on error
*/
private I2NPMessage readMessage(ByteArray buf, InboundMessageState state, I2NPMessageHandler handler) {
try {
// byte buf[] = new byte[state.getCompleteSize()];
I2NPMessage m;
int numFragments = state.getFragmentCount();
if (numFragments > 1) {
ByteArray[] fragments = state.getFragments();
int off = 0;
for (int i = 0; i < numFragments; i++) {
System.arraycopy(fragments[i].getData(), 0, buf.getData(), off, fragments[i].getValid());
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Raw fragment[" + i + "] for " + state.getMessageId() + ": "
// + Base64.encode(fragments[i].getData(), 0, fragments[i].getValid())
// + " (valid: " + fragments[i].getValid()
// + " raw: " + Base64.encode(fragments[i].getData()) + ")");
off += fragments[i].getValid();
}
if (off != state.getCompleteSize()) {
if (_log.shouldLog(Log.WARN))
_log.warn("Hmm, offset of the fragments = " + off + " while the state says " + state.getCompleteSize());
return null;
}
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Raw byte array for " + state.getMessageId() + ": " + HexDump.dump(buf.getData(), 0, state.getCompleteSize()));
m = I2NPMessageImpl.fromRawByteArray(_context, buf.getData(), 0, state.getCompleteSize(), handler);
} else {
// zero copy for single fragment
m = I2NPMessageImpl.fromRawByteArray(_context, state.getFragments()[0].getData(), 0, state.getCompleteSize(), handler);
}
m.setUniqueId(state.getMessageId());
return m;
} catch (I2NPMessageException ime) {
if (_log.shouldLog(Log.WARN)) {
ByteArray ba;
if (state.getFragmentCount() > 1)
ba = buf;
else
ba = state.getFragments()[0];
byte[] data = ba.getData();
_log.warn("Message invalid: " + state + " PeerState: " + _transport.getPeerState(state.getFrom()) + "\nDUMP:\n" + HexDump.dump(data, 0, state.getCompleteSize()) + "\nRAW:\n" + Base64.encode(data, 0, state.getCompleteSize()), ime);
}
if (state.getFragments()[0].getData()[0] == DatabaseStoreMessage.MESSAGE_TYPE) {
PeerState ps = _transport.getPeerState(state.getFrom());
if (ps != null && ps.getRemotePort() == 65520) {
// distinct port of buggy router
_transport.sendDestroy(ps);
_transport.dropPeer(ps, true, "Corrupt DSM");
_context.banlist().banlistRouterForever(state.getFrom(), _x("Sent corrupt DSM"));
}
}
_context.messageHistory().droppedInboundMessage(state.getMessageId(), state.getFrom(), "error: " + ime.toString() + ": " + state.toString());
return null;
} catch (RuntimeException e) {
// e.g. AIOOBE
if (_log.shouldLog(Log.WARN))
_log.warn("Error handling a message: " + state, e);
_context.messageHistory().droppedInboundMessage(state.getMessageId(), state.getFrom(), "error: " + e.toString() + ": " + state.toString());
return null;
} finally {
state.releaseResources();
}
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class MessageReceiver method loop.
public void loop(I2NPMessageHandler handler) {
InboundMessageState message = null;
// ByteArray buf = _cache.acquire();
ByteArray buf = new ByteArray(new byte[I2NPMessage.MAX_SIZE]);
while (_alive) {
int expired = 0;
long expiredLifetime = 0;
try {
while (message == null) {
message = _completeMessages.take();
if ((message != null) && (message.getMessageId() == POISON_IMS)) {
message = null;
break;
}
if ((message != null) && (message.isExpired())) {
expiredLifetime += message.getLifetime();
// message.releaseResources() ??
message = null;
expired++;
}
// remaining = _completeMessages.size();
}
} catch (InterruptedException ie) {
}
if (expired > 0)
_context.statManager().addRateData("udp.inboundExpired", expired, expiredLifetime);
if (message != null) {
// long before = System.currentTimeMillis();
// if (remaining > 0)
// _context.statManager().addRateData("udp.inboundRemaining", remaining, 0);
int size = message.getCompleteSize();
// long afterRead = -1;
try {
I2NPMessage msg = readMessage(buf, message, handler);
// afterRead = System.currentTimeMillis();
if (msg != null)
_transport.messageReceived(msg, null, message.getFrom(), message.getLifetime(), size);
} catch (RuntimeException re) {
_log.error("b0rked receiving a message.. wazza huzza hmm?", re);
continue;
}
message = null;
// long after = System.currentTimeMillis();
// if (afterRead - before > 100)
// _context.statManager().addRateData("udp.inboundReadTime", afterRead - before, remaining);
// if (after - afterRead > 100)
// _context.statManager().addRateData("udp.inboundReceiveProcessTime", after - afterRead, remaining);
}
}
// no need to zero it out, as these buffers are only used with an explicit getCompleteSize
// _cache.release(buf, false);
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class NTCPConnection method bufferedPrepare.
/**
* Serialize the message/checksum/padding/etc for transmission, but leave off
* the encryption. This should be called from a Writer thread
*
* @param msg message to send
* @param buf PrepBuffer to use as scratch space
*/
private void bufferedPrepare(OutNetMessage msg, PrepBuffer buf) {
// if (!_isInbound && !_established)
// return;
// long begin = System.currentTimeMillis();
// long alloc = System.currentTimeMillis();
I2NPMessage m = msg.getMessage();
buf.baseLength = m.toByteArray(buf.base);
int sz = buf.baseLength;
// int sz = m.getMessageSize();
int min = 2 + sz + 4;
int rem = min % 16;
int padding = 0;
if (rem > 0)
padding = 16 - rem;
buf.unencryptedLength = min + padding;
DataHelper.toLong(buf.unencrypted, 0, 2, sz);
System.arraycopy(buf.base, 0, buf.unencrypted, 2, buf.baseLength);
if (padding > 0) {
_context.random().nextBytes(buf.unencrypted, 2 + sz, padding);
}
// long serialized = System.currentTimeMillis();
buf.crc.update(buf.unencrypted, 0, buf.unencryptedLength - 4);
long val = buf.crc.getValue();
if (_log.shouldLog(Log.DEBUG))
_log.debug("Outbound message " + _messagesWritten + " has crc " + val + " sz=" + sz + " rem=" + rem + " padding=" + padding);
DataHelper.toLong(buf.unencrypted, buf.unencryptedLength - 4, 4, val);
// TODO object churn
// 1) store the length only
// 2) in prepareNextWriteFast(), pull a byte buffer off a queue and encrypt to that
// 3) change EventPumper.wantsWrite() to take a ByteBuffer arg
// 4) in EventPumper.processWrite(), release the byte buffer
buf.encrypted = new byte[buf.unencryptedLength];
// long crced = System.currentTimeMillis();
// if (_log.shouldLog(Log.DEBUG))
// _log.debug("Buffered prepare took " + (crced-begin) + ", alloc=" + (alloc-begin)
// + " serialize=" + (serialized-alloc) + " crc=" + (crced-serialized));
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class FloodfillVerifyStoreJob method runJob.
/**
* Query a random floodfill for the leaseset or routerinfo
* that we just stored to a (hopefully different) floodfill peer.
*
* If it fails (after a timeout period), resend the data.
* If the queried data is older than what we stored, that counts as a fail.
*/
public void runJob() {
_target = pickTarget();
if (_target == null) {
_facade.verifyFinished(_key);
return;
}
boolean isInboundExploratory;
TunnelInfo replyTunnelInfo;
if (_isRouterInfo || getContext().keyRing().get(_key) != null) {
replyTunnelInfo = getContext().tunnelManager().selectInboundExploratoryTunnel(_target);
isInboundExploratory = true;
} else {
replyTunnelInfo = getContext().tunnelManager().selectInboundTunnel(_key, _target);
isInboundExploratory = false;
}
if (replyTunnelInfo == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No inbound tunnels to get a reply from!");
return;
}
DatabaseLookupMessage lookup = buildLookup(replyTunnelInfo);
// If we are verifying a leaseset, use the destination's own tunnels,
// to avoid association by the exploratory tunnel OBEP.
// Unless it is an encrypted leaseset.
TunnelInfo outTunnel;
if (_isRouterInfo || getContext().keyRing().get(_key) != null)
outTunnel = getContext().tunnelManager().selectOutboundExploratoryTunnel(_target);
else
outTunnel = getContext().tunnelManager().selectOutboundTunnel(_key, _target);
if (outTunnel == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No outbound tunnels to verify a store");
_facade.verifyFinished(_key);
return;
}
// garlic encrypt to hide contents from the OBEP
RouterInfo peer = _facade.lookupRouterInfoLocally(_target);
if (peer == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Fail finding target RI");
_facade.verifyFinished(_key);
return;
}
if (DatabaseLookupMessage.supportsEncryptedReplies(peer)) {
// register the session with the right SKM
MessageWrapper.OneTimeSession sess;
if (isInboundExploratory) {
sess = MessageWrapper.generateSession(getContext());
} else {
sess = MessageWrapper.generateSession(getContext(), _key);
if (sess == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("No SKM to reply to");
_facade.verifyFinished(_key);
return;
}
}
if (_log.shouldLog(Log.INFO))
_log.info("Requesting encrypted reply from " + _target + ' ' + sess.key + ' ' + sess.tag);
lookup.setReplySession(sess.key, sess.tag);
}
Hash fromKey;
if (_isRouterInfo)
fromKey = null;
else
fromKey = _key;
_wrappedMessage = MessageWrapper.wrap(getContext(), lookup, fromKey, peer);
if (_wrappedMessage == null) {
if (_log.shouldLog(Log.WARN))
_log.warn("Fail Garlic encrypting");
_facade.verifyFinished(_key);
return;
}
I2NPMessage sent = _wrappedMessage.getMessage();
if (_log.shouldLog(Log.INFO))
_log.info("Starting verify (stored " + _key + " to " + _sentTo + "), asking " + _target);
_sendTime = getContext().clock().now();
_expiration = _sendTime + VERIFY_TIMEOUT;
getContext().messageRegistry().registerPending(new VerifyReplySelector(), new VerifyReplyJob(getContext()), new VerifyTimeoutJob(getContext()));
getContext().tunnelDispatcher().dispatchOutbound(sent, outTunnel.getSendTunnelId(0), _target);
}
use of net.i2p.data.i2np.I2NPMessage in project i2p.i2p by i2p.
the class VMCommSystem method processMessage.
/**
* The router wants us to send the given message to the peer. Do so, or fire
* off the failing job.
*/
public void processMessage(OutNetMessage msg) {
Hash peer = msg.getTarget().getIdentity().getHash();
VMCommSystem peerSys = _commSystemFacades.get(peer);
long now = _context.clock().now();
long sendTime = now - msg.getSendBegin();
boolean sendSuccessful = false;
if (peerSys == null) {
_context.jobQueue().addJob(msg.getOnFailedSendJob());
_context.statManager().updateFrequency("transport.sendMessageFailureFrequency");
_context.profileManager().messageFailed(msg.getTarget().getIdentity().getHash(), "vm");
} else {
_context.jobQueue().addJob(msg.getOnSendJob());
_context.profileManager().messageSent(msg.getTarget().getIdentity().getHash(), "vm", sendTime, msg.getMessageSize());
byte[] data = new byte[(int) msg.getMessageSize()];
msg.getMessageData(data);
_context.statManager().addRateData("transport.sendMessageSize", data.length, sendTime);
if (data.length < 1024)
_context.statManager().addRateData("transport.sendMessageSmall", 1, sendTime);
else if (data.length <= 4096)
_context.statManager().addRateData("transport.sendMessageMedium", 1, sendTime);
else
_context.statManager().addRateData("transport.sendMessageLarge", 1, sendTime);
peerSys.receive(data, _context.routerHash());
// _context.jobQueue().addJob(new SendJob(peerSys, msg.getMessage(), _context));
sendSuccessful = true;
}
if (true) {
I2NPMessage dmsg = msg.getMessage();
String type = dmsg.getClass().getName();
_context.messageHistory().sendMessage(type, dmsg.getUniqueId(), dmsg.getMessageExpiration(), msg.getTarget().getIdentity().getHash(), sendSuccessful, null);
}
msg.discardData();
_context.statManager().addRateData("transport.sendProcessingTime", msg.getLifetime(), msg.getLifetime());
}
Aggregations