diff --git a/router/java/src/net/i2p/router/OutNetMessage.java b/router/java/src/net/i2p/router/OutNetMessage.java index 3c0a77a2bb..0cc8a7d89a 100644 --- a/router/java/src/net/i2p/router/OutNetMessage.java +++ b/router/java/src/net/i2p/router/OutNetMessage.java @@ -36,7 +36,7 @@ public class OutNetMessage implements CDPQEntry { private final int _messageTypeId; /** cached message ID, for use after we discard the message */ private final long _messageId; - private final long _messageSize; + private final int _messageSize; private final int _priority; private final long _expiration; private Job _onSend; @@ -200,14 +200,17 @@ public class OutNetMessage implements CDPQEntry { * @return the simple class name */ public String getMessageType() { - I2NPMessage msg = _message; - return msg != null ? msg.getClass().getSimpleName() : "null"; + return _message != null ? _message.getClass().getSimpleName() : "null"; } public int getMessageTypeId() { return _messageTypeId; } public long getMessageId() { return _messageId; } - public long getMessageSize() { + /** + * How large the message is, including the full 16 byte header. + * Transports with different header sizes should adjust. + */ + public int getMessageSize() { return _messageSize; } diff --git a/router/java/src/net/i2p/router/transport/Transport.java b/router/java/src/net/i2p/router/transport/Transport.java index b5738445dd..efeb10ec71 100644 --- a/router/java/src/net/i2p/router/transport/Transport.java +++ b/router/java/src/net/i2p/router/transport/Transport.java @@ -28,7 +28,16 @@ import net.i2p.router.OutNetMessage; * */ public interface Transport { - public TransportBid bid(RouterInfo toAddress, long dataSize); + + /** + * + * @param dataSize assumes full 16-byte header, transports should + * adjust as necessary + * @return a bid or null if unwilling to send + * + */ + public TransportBid bid(RouterInfo toAddress, int dataSize); + /** * Asynchronously send the message as requested in the message and, if the * send is successful, queue up any msg.getOnSendJob job, and register it diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java index 2b3a407bab..26e7a863cb 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPConnection.java @@ -161,11 +161,11 @@ public class NTCPConnection implements Closeable { * Needs to be fixed. But SSU can handle it? * In the meantime, don't let the transport bid on big messages. */ - public static final int BUFFER_SIZE = 16*1024; + static final int BUFFER_SIZE = 16*1024; private static final int MAX_DATA_READ_BUFS = 16; private static final ByteCache _dataReadBufs = ByteCache.getInstance(MAX_DATA_READ_BUFS, BUFFER_SIZE); /** 2 bytes for length and 4 for CRC */ - public static final int MAX_MSG_SIZE = BUFFER_SIZE - (2 + 4); + static final int NTCP1_MAX_MSG_SIZE = BUFFER_SIZE - (2 + 4); private static final int INFO_PRIORITY = OutNetMessage.PRIORITY_MY_NETDB_STORE_LOW; private static final String FIXED_RI_VERSION = "0.9.12"; @@ -174,12 +174,19 @@ public class NTCPConnection implements Closeable { //// NTCP2 things + /** See spec. Max Noise payload 65535, + * minus 16 byte MAC and 3 byte block header. + * Includes 9-byte I2NP header. + */ + static final int NTCP2_MAX_MSG_SIZE = 65516; private static final int PADDING_RAND_MIN = 16; private static final int PADDING_MAX = 64; private static final int SIP_IV_LENGTH = 8; private static final int NTCP2_FAIL_READ = 1024; private static final long NTCP2_FAIL_TIMEOUT = 10*1000; private static final long NTCP2_TERMINATION_CLOSE_DELAY = 50; + // don't make combined messages too big, to minimize latency + private static final int NTCP2_PREFERRED_PAYLOAD_MAX = 5000; static final int REASON_UNSPEC = 0; static final int REASON_TERMINATION = 1; static final int REASON_TIMEOUT = 2; @@ -832,14 +839,12 @@ public class NTCPConnection implements Closeable { _transport.afterSend(msg, false, false, msg.getLifetime()); } _currentOutbound.add(msg); - // don't make combined msgs too big to minimize latency - final int MAX_MSG_SIZE = 5000; I2NPMessage m = msg.getMessage(); Block block = new NTCP2Payload.I2NPBlock(m); blocks.add(block); size += block.getTotalLength(); // now add more (maybe) - if (size < MAX_MSG_SIZE) { + if (size < NTCP2_PREFERRED_PAYLOAD_MAX) { // keep adding as long as we will be under 5 KB while (true) { msg = _outbound.peek(); @@ -847,7 +852,7 @@ public class NTCPConnection implements Closeable { break; m = msg.getMessage(); int msz = m.getMessageSize() - 7; - if (size + msz > MAX_MSG_SIZE) + if (size + msz > NTCP2_PREFERRED_PAYLOAD_MAX) break; OutNetMessage msg2 = _outbound.poll(); if (msg2 == null) diff --git a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java index ade45ee683..040f2b4ff6 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java +++ b/router/java/src/net/i2p/router/transport/ntcp/NTCPTransport.java @@ -459,11 +459,15 @@ public class NTCPTransport extends TransportImpl { super.afterSend(msg, sendSuccessful, allowRequeue, msToSend); } - public TransportBid bid(RouterInfo toAddress, long dataSize) { + public TransportBid bid(RouterInfo toAddress, int dataSize) { if (!isAlive()) return null; - if (dataSize > NTCPConnection.MAX_MSG_SIZE) { - // let SSU deal with it + // passed in dataSize assumes 16 byte header, if NTCP2 then + // we have a 9-byte header so there's 7 to spare + if (dataSize > NTCPConnection.NTCP2_MAX_MSG_SIZE + 7 || + (!_enableNTCP2 && dataSize > NTCPConnection.NTCP1_MAX_MSG_SIZE)) { + // Too big for NTCP2, or NTCP2 disabled and too big for NTCP1 + // Let SSU deal with it _context.statManager().addRateData("ntcp.noBidTooLargeI2NP", dataSize); return null; } @@ -478,12 +482,24 @@ public class NTCPTransport extends TransportImpl { return null; } - boolean established = isEstablished(toAddress.getIdentity()); + boolean established = isEstablished(peer); if (established) { // should we check the queue size? nah, if its valid, use it - //if (_log.shouldLog(Log.DEBUG)) - // _log.debug("fast bid when trying to send to " + peer + " as its already established"); + if (dataSize > NTCPConnection.NTCP1_MAX_MSG_SIZE) { + // Must be version 2 to send a big message + NTCPConnection con = _conByIdent.get(peer); + if (con == null || con.getVersion() < NTCP2_INT_VERSION) { + _context.statManager().addRateData("ntcp.noBidTooLargeI2NP", dataSize); + return null; + } + } return _fastBid; } + if (dataSize > NTCPConnection.NTCP1_MAX_MSG_SIZE) { + // Not established, too big for NTCP 1, let SSU deal with it + // TODO look at his addresses to see if NTCP2 supported? + _context.statManager().addRateData("ntcp.noBidTooLargeI2NP", dataSize); + return null; + } RouterAddress addr = getTargetAddress(toAddress); if (addr == null) { diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index ddc3862699..fde8d92d26 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -1739,7 +1739,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } - public TransportBid bid(RouterInfo toAddress, long dataSize) { + public TransportBid bid(RouterInfo toAddress, int dataSize) { if (dataSize > OutboundMessageState.MAX_MSG_SIZE) { // NTCP max is lower, so msg will get dropped return null;