package net.i2p.router.dummy; import java.io.IOException; import java.io.Writer; import java.util.Collections; import java.util.HashMap; import java.util.Map; import net.i2p.data.Hash; import net.i2p.data.i2np.I2NPMessage; import net.i2p.data.i2np.I2NPMessageException; import net.i2p.data.i2np.I2NPMessageHandler; import net.i2p.router.CommSystemFacade; import net.i2p.router.JobImpl; import net.i2p.router.OutNetMessage; import net.i2p.router.RouterContext; import net.i2p.util.Log; /** * Hacked up in-VM comm system for talking between contexts. It doesn't even * generate any routerAddresses, but instead tracks the peers through a singleton. * Currently, the comm system doesn't even inject any lag, though it could (later). * It does honor the standard transport stats though, but not the TCP specific ones. * * FOR DEBUGGING AND LOCAL TESTING ONLY. */ public class VMCommSystem extends CommSystemFacade { private final Log _log; private final RouterContext _context; /** * Mapping from Hash to VMCommSystem for all routers hooked together */ private static Map<Hash, VMCommSystem> _commSystemFacades = Collections.synchronizedMap(new HashMap<Hash, VMCommSystem>(16)); public VMCommSystem(RouterContext context) { _context = context; _log = context.logManager().getLog(VMCommSystem.class); _context.statManager().createFrequencyStat("transport.sendMessageFailureFrequency", "How often do we fail to send messages?", "Transport", new long[] { 60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRequiredRateStat("transport.sendMessageSize", "Size of sent messages (bytes)", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRequiredRateStat("transport.receiveMessageSize", "Size of received messages (bytes)", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("transport.sendMessageSmall", "How many messages under 1KB are sent?", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("transport.receiveMessageSmall", "How many messages under 1KB are received?", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("transport.sendMessageMedium", "How many messages between 1KB and 4KB are sent?", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("transport.receiveMessageMedium", "How many messages between 1KB and 4KB are received?", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("transport.sendMessageLarge", "How many messages over 4KB are sent?", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRateStat("transport.receiveMessageLarge", "How many messages over 4KB are received?", "Transport", new long[] { 60*1000l, 5*60*1000l, 60*60*1000l, 24*60*60*1000l }); _context.statManager().createRequiredRateStat("transport.sendProcessingTime", "Time to process and send a message (ms)", "Transport", new long[] { 60*1000l, 10*60*1000l, 60*60*1000l, 24*60*60*1000l }); } /** * 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()); } private class ReceiveJob extends JobImpl { private Hash _from; private byte _msg[]; private RouterContext _ctx; public ReceiveJob(Hash from, byte msg[], RouterContext us) { super(us); _ctx = us; _from = from; _msg = msg; // bah, ueberspeed! getTiming().setStartAfter(us.clock().now()); } public void runJob() { I2NPMessageHandler handler = new I2NPMessageHandler(_ctx); try { I2NPMessage msg = handler.readMessage(_msg); int size = _msg.length; _ctx.profileManager().messageReceived(_from, "vm", 1, size); _ctx.statManager().addRateData("transport.receiveMessageSize", size, 1); if (size < 1024) ReceiveJob.this.getContext().statManager().addRateData("transport.receiveMessageSmall", 1, 1); else if (size <= 4096) ReceiveJob.this.getContext().statManager().addRateData("transport.receiveMessageMedium", 1, 1); else ReceiveJob.this.getContext().statManager().addRateData("transport.receiveMessageLarge", 1, 1); _ctx.inNetMessagePool().add(msg, null, _from); } catch (I2NPMessageException e) { _log.error("Error reading/formatting a VM message? Something is not right...", e); } } public String getName() { return "Receive Message"; } } /** * We send messages between comms as bytes so that we strip any router-local * info. For example, a router tags the # attempts to send through a * leaseSet, what type of tunnel a tunnelId is bound to, etc. * */ public void receive(byte message[], Hash fromPeer) { _context.jobQueue().addJob(new ReceiveJob(fromPeer, message, _context)); } public void shutdown() { _commSystemFacades.remove(_context.routerHash()); } public void startup() { _commSystemFacades.put(_context.routerHash(), this); } public void restart() { _commSystemFacades.remove(_context.routerHash()); _commSystemFacades.put(_context.routerHash(), this); } public void renderStatusHTML(Writer out, String urlBase, int sortFlags) throws IOException { out.write("Dummy! i2p.vmCommSystem=true!"); } }