/** write the message body to the output array, starting at the given index */ protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException { if ((_tunnelId == null) || ((_msg == null) && (_msgData == null))) { _log.log(Log.CRIT, "failing to write out gateway message"); throw new I2NPMessageException( "Not enough data to write out (id=" + _tunnelId + " data=" + _msg + ")"); } DataHelper.toLong(out, curIndex, 4, _tunnelId.getTunnelId()); curIndex += 4; synchronized (this) { if (_msgData == null) { _msgData = _msg.toByteArray(); _msg = null; } } DataHelper.toLong(out, curIndex, 2, _msgData.length); curIndex += 2; // where is this coming from? if (curIndex + _msgData.length > out.length) { _log.log( Log.ERROR, "output buffer too small idx: " + curIndex + " len: " + _msgData.length + " outlen: " + out.length); throw new I2NPMessageException( "Too much data to write out (id=" + _tunnelId + " data=" + _msg + ")"); } System.arraycopy(_msgData, 0, out, curIndex, _msgData.length); curIndex += _msgData.length; return curIndex; }
/** * The local router has detected a failure in the given tunnel * * @param tunnel tunnel failed */ public void tunnelFailed(TunnelId tunnel) { if (!_doLog) return; if (tunnel == null) return; StringBuilder buf = new StringBuilder(128); buf.append(getPrefix()); buf.append("failing tunnel [").append(tunnel.getTunnelId()).append("]"); addEntry(buf.toString()); }
/** * The peer did not accept the tunnel join for the given reason (this may be because of a timeout * or an explicit refusal). */ public void tunnelRequestTimedOut(Hash peer, TunnelId tunnel) { if (!_doLog) return; if ((tunnel == null) || (peer == null)) return; StringBuilder buf = new StringBuilder(128); buf.append(getPrefix()); buf.append("tunnel [").append(tunnel.getTunnelId()).append("] timed out on ["); buf.append(getName(peer)).append("]"); addEntry(buf.toString()); }
@Override protected void doReadMessage(InputStream in, int size) throws I2CPMessageException, IOException { try { _sessionId = new SessionId(); _sessionId.readBytes(in); int numTunnels = (int) DataHelper.readLong(in, 1); _endpoints.clear(); for (int i = 0; i < numTunnels; i++) { // Hash router = new Hash(); // router.readBytes(in); Hash router = Hash.create(in); TunnelId tunnel = new TunnelId(); tunnel.readBytes(in); _endpoints.add(new TunnelEndpoint(router, tunnel)); } _end = DataHelper.readDate(in); } catch (DataFormatException dfe) { throw new I2CPMessageException("Unable to load the message data", dfe); } }
@Override protected byte[] doWriteMessage() throws I2CPMessageException, IOException { if (_sessionId == null) throw new I2CPMessageException("Unable to write out the message as there is not enough data"); ByteArrayOutputStream os = new ByteArrayOutputStream(256); try { _sessionId.writeBytes(os); DataHelper.writeLong(os, 1, _endpoints.size()); for (int i = 0; i < _endpoints.size(); i++) { Hash router = getRouter(i); router.writeBytes(os); TunnelId tunnel = getTunnelId(i); tunnel.writeBytes(os); } DataHelper.writeDate(os, _end); } catch (DataFormatException dfe) { throw new I2CPMessageException("Error writing out the message data", dfe); } return os.toByteArray(); }
/** * We don't know about the given tunnel, so we are dropping a message sent to us by the given * router * * @param id tunnel ID we received a message for * @param from peer that sent us this message (if known) */ public void droppedTunnelMessage(TunnelId id, long msgId, Date expiration, Hash from) { if (!_doLog) return; StringBuilder buf = new StringBuilder(128); buf.append(getPrefix()); buf.append("dropped message ") .append(msgId) .append(" for unknown tunnel [") .append(id.getTunnelId()); buf.append("] from [").append(getName(from)).append("]").append(" expiring on "); buf.append(getTime(expiration.getTime())); addEntry(buf.toString()); }
/** The peer did not accept the tunnel join for the given reason */ public void tunnelRejected(Hash peer, TunnelId tunnel, Hash replyThrough, String reason) { if (!_doLog) return; if ((tunnel == null) || (peer == null)) return; StringBuilder buf = new StringBuilder(128); buf.append(getPrefix()); buf.append("tunnel [").append(tunnel.getTunnelId()).append("] was rejected by ["); buf.append(getName(peer)).append("] for [").append(reason).append("]"); if (replyThrough != null) buf.append(" with their reply intended to come through [") .append(getName(replyThrough)) .append("]"); addEntry(buf.toString()); }
/** * Note that for efficiency at the IBGW, this does not fully deserialize the included I2NP * Message. It just puts it in an UnknownI2NPMessage. * * @param handler unused, may be null */ @Override public void readMessage( byte data[], int offset, int dataSize, int type, I2NPMessageHandler handler) throws I2NPMessageException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); int curIndex = offset; _tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); curIndex += 4; if (_tunnelId.getTunnelId() <= 0) throw new I2NPMessageException("Invalid tunnel Id " + _tunnelId); int len = (int) DataHelper.fromLong(data, curIndex, 2); curIndex += 2; if (len <= 1 || curIndex + len > data.length || len > dataSize - 6) throw new I2NPMessageException( "I2NP length in TGM: " + len + " but remaining bytes: " + Math.min(data.length - curIndex, dataSize - 6)); // OLD WAY full message parsing and instantiation // handler.readMessage(data, curIndex); // _msg = handler.lastRead(); // if (_msg == null) // throw new I2NPMessageException("impossible? message read has no payload?!"); // NEW WAY save lots of effort at the IBGW by reading as an UnknownI2NPMessage instead // This will save a lot of object churn and processing, // primarily for unencrypted msgs (V)TBRM, DatabaseStoreMessage, and DSRMs. // DatabaseStoreMessages in particluar are intensive for readBytes() // since the RI is decompressed. // For a zero-hop IB tunnel, where we do need the real thing, // it is converted to a real message class in TunnelGatewayZeroHop // using UnknownI2NPMessage.convert() in TunnelGatewayZeroHop. // We also skip processing the checksum as it's covered by the TGM checksum. // If a zero-hop, the checksum will be verified in convert(). int utype = data[curIndex++] & 0xff; UnknownI2NPMessage umsg = new UnknownI2NPMessage(_context, utype); umsg.readBytes(data, utype, curIndex); _msg = umsg; }
/** * Add a message to be sent down the tunnel (immediately forwarding it to the {@link * InboundMessageDistributor} or {@link OutboundMessageDistributor}, as necessary). * * @param msg message to be sent through the tunnel * @param toRouter router to send to after the endpoint (or null for endpoint processing) * @param toTunnel tunnel to send to after the endpoint (or null for endpoint or router * processing) */ @Override public void add(I2NPMessage msg, Hash toRouter, TunnelId toTunnel) { if (_log.shouldLog(Log.DEBUG)) _log.debug( "zero hop gateway: distribute " + (_config.isInbound() ? "inbound" : " outbound") + " to " + (toRouter != null ? toRouter.toBase64().substring(0, 4) : "") + "." + (toTunnel != null ? toTunnel.getTunnelId() + "" : "") + ": " + msg); if (_config.isInbound()) { _inDistributor.distribute(msg, toRouter, toTunnel); } else { _outDistributor.distribute(msg, toRouter, toTunnel); } _config.incrementProcessedMessages(); }
public void setReceiveTunnelId(TunnelId id) { _receiveTunnelId = DataHelper.toLong(4, id.getTunnelId()); }