- Revert change in UDPPacket that caused massive corruption
    - Reduce buffer sizes from 2048 to 1536
    - Discard too-large received packets sooner
    - More cleanups
    - Notes on MTU
This commit is contained in:
zzz
2011-07-24 15:15:19 +00:00
parent ec061eb3e0
commit 89d32e3bef
5 changed files with 60 additions and 15 deletions

View File

@ -33,7 +33,8 @@ class InboundMessageState {
private static final long MAX_RECEIVE_TIME = 10*1000; private static final long MAX_RECEIVE_TIME = 10*1000;
public static final int MAX_FRAGMENTS = 64; public static final int MAX_FRAGMENTS = 64;
private static final ByteCache _fragmentCache = ByteCache.getInstance(64, 2048); private static final int MAX_FRAGMENT_SIZE = UDPPacket.MAX_PACKET_SIZE;
private static final ByteCache _fragmentCache = ByteCache.getInstance(64, MAX_FRAGMENT_SIZE);
public InboundMessageState(RouterContext ctx, long messageId, Hash from) { public InboundMessageState(RouterContext ctx, long messageId, Hash from) {
_context = ctx; _context = ctx;

View File

@ -157,7 +157,7 @@ class PeerState {
/* how many consecutive packets at or under the min MTU have been received */ /* how many consecutive packets at or under the min MTU have been received */
private long _consecutiveSmall; private long _consecutiveSmall;
/** when did we last check the MTU? */ /** when did we last check the MTU? */
private long _mtuLastChecked; //private long _mtuLastChecked;
private long _mtuIncreases; private long _mtuIncreases;
private long _mtuDecreases; private long _mtuDecreases;
/** current round trip time estimate */ /** current round trip time estimate */
@ -224,7 +224,7 @@ class PeerState {
* of 608 * of 608
* *
* Well, we really need to count the acks as well, especially * Well, we really need to count the acks as well, especially
* 4 * MAX_RESEND_ACKS which can take up a significant amount of space. * 1 + (4 * MAX_RESEND_ACKS_SMALL) which can take up a significant amount of space.
* We reduce the max acks when using the small MTU but it may not be enough... * We reduce the max acks when using the small MTU but it may not be enough...
* *
*/ */
@ -234,6 +234,12 @@ class PeerState {
* based on measurements, 1350 fits nearly all reasonably small I2NP messages * based on measurements, 1350 fits nearly all reasonably small I2NP messages
* (larger I2NP messages may be up to 1900B-4500B, which isn't going to fit * (larger I2NP messages may be up to 1900B-4500B, which isn't going to fit
* into a live network MTU anyway) * into a live network MTU anyway)
*
* TODO
* VTBM is 2646, it would be nice to fit in two large
* 2646 / 2 = 1323
* 1323 + 74 + 46 + 1 + (4 * 9) = 1480
* So why not make it 1492 (old ethernet is 1492, new is 1500)
*/ */
private static final int LARGE_MTU = 1350; private static final int LARGE_MTU = 1350;
@ -261,7 +267,7 @@ class PeerState {
_remotePort = -1; _remotePort = -1;
_mtu = getDefaultMTU(); _mtu = getDefaultMTU();
_mtuReceive = _mtu; _mtuReceive = _mtu;
_mtuLastChecked = -1; //_mtuLastChecked = -1;
_lastACKSend = -1; _lastACKSend = -1;
_rto = MIN_RTO; _rto = MIN_RTO;
_rtt = _rto/2; _rtt = _rto/2;
@ -370,13 +376,20 @@ class PeerState {
public long getTheyRelayToUsAs() { return _theyRelayToUsAs; } public long getTheyRelayToUsAs() { return _theyRelayToUsAs; }
/** what is the largest packet we can send to the peer? */ /** what is the largest packet we can send to the peer? */
public int getMTU() { return _mtu; } public int getMTU() { return _mtu; }
/** estimate how large the other side is sending packets */
/**
* Estimate how large the other side's MTU is.
* This could be wrong.
* It is used only for the HTML status.
*/
public int getReceiveMTU() { return _mtuReceive; } public int getReceiveMTU() { return _mtuReceive; }
/** when did we last check the MTU? */ /** when did we last check the MTU? */
/****
public long getMTULastChecked() { return _mtuLastChecked; } public long getMTULastChecked() { return _mtuLastChecked; }
public long getMTUIncreases() { return _mtuIncreases; } public long getMTUIncreases() { return _mtuIncreases; }
public long getMTUDecreases() { return _mtuDecreases; } public long getMTUDecreases() { return _mtuDecreases; }
****/
/** /**
* The peer are we talking to. This should be set as soon as this * The peer are we talking to. This should be set as soon as this
@ -537,11 +550,15 @@ class PeerState {
* we can use to publish that fact. * we can use to publish that fact.
*/ */
public void setTheyRelayToUsAs(long tag) { _theyRelayToUsAs = tag; } public void setTheyRelayToUsAs(long tag) { _theyRelayToUsAs = tag; }
/** what is the largest packet we can send to the peer? */ /** what is the largest packet we can send to the peer? */
/****
public void setMTU(int mtu) { public void setMTU(int mtu) {
_mtu = mtu; _mtu = mtu;
_mtuLastChecked = _context.clock().now(); _mtuLastChecked = _context.clock().now();
} }
****/
public int getSlowStartThreshold() { return _slowStartThreshold; } public int getSlowStartThreshold() { return _slowStartThreshold; }
public int getConcurrentSends() { return _concurrentMessagesActive; } public int getConcurrentSends() { return _concurrentMessagesActive; }
public int getConcurrentSendWindow() { return _concurrentMessagesAllowed; } public int getConcurrentSendWindow() { return _concurrentMessagesAllowed; }
@ -979,15 +996,21 @@ class PeerState {
public long getPacketRetransmissionRate() { return _packetRetransmissionRate; } public long getPacketRetransmissionRate() { return _packetRetransmissionRate; }
public long getPacketsReceived() { return _packetsReceived; } public long getPacketsReceived() { return _packetsReceived; }
public long getPacketsReceivedDuplicate() { return _packetsReceivedDuplicate; } public long getPacketsReceivedDuplicate() { return _packetsReceivedDuplicate; }
private static final int MTU_RCV_DISPLAY_THRESHOLD = 20;
public void packetReceived(int size) { public void packetReceived(int size) {
_packetsReceived++; _packetsReceived++;
if (size <= MIN_MTU) if (size <= MIN_MTU) {
_consecutiveSmall++; _consecutiveSmall++;
else } else {
_consecutiveSmall = 0; _consecutiveSmall = 0;
_mtuReceive = LARGE_MTU;
return;
}
if (_packetsReceived > 50) { if (_packetsReceived > MTU_RCV_DISPLAY_THRESHOLD) {
if (_consecutiveSmall < 50) if (_consecutiveSmall < MTU_RCV_DISPLAY_THRESHOLD)
_mtuReceive = LARGE_MTU; _mtuReceive = LARGE_MTU;
else else
_mtuReceive = MIN_MTU; _mtuReceive = MIN_MTU;
@ -1287,7 +1310,11 @@ class PeerState {
private static final int SSU_HEADER_SIZE = 46; private static final int SSU_HEADER_SIZE = 46;
static final int UDP_HEADER_SIZE = 8; static final int UDP_HEADER_SIZE = 8;
static final int IP_HEADER_SIZE = 20; static final int IP_HEADER_SIZE = 20;
/** how much payload data can we shove in there? */
/**
* how much payload data can we shove in there?
* @return MTU - 74
*/
private static final int fragmentSize(int mtu) { private static final int fragmentSize(int mtu) {
return mtu - SSU_HEADER_SIZE - UDP_HEADER_SIZE - IP_HEADER_SIZE; return mtu - SSU_HEADER_SIZE - UDP_HEADER_SIZE - IP_HEADER_SIZE;
} }
@ -1296,7 +1323,7 @@ class PeerState {
long now = _context.clock().now(); long now = _context.clock().now();
if (state.getNextSendTime() <= now) { if (state.getNextSendTime() <= now) {
if (!state.isFragmented()) { if (!state.isFragmented()) {
state.fragment(fragmentSize(getMTU())); state.fragment(fragmentSize(_mtu));
if (state.getMessage() != null) if (state.getMessage() != null)
state.getMessage().timestamp("fragment into " + state.getFragmentCount()); state.getMessage().timestamp("fragment into " + state.getFragmentCount());

View File

@ -51,7 +51,13 @@ class UDPPacket {
_log = I2PAppContext.getGlobalContext().logManager().getLog(UDPPacket.class); _log = I2PAppContext.getGlobalContext().logManager().getLog(UDPPacket.class);
} }
static final int MAX_PACKET_SIZE = 2048; /**
* Actually it is one less than this, we assume
* if a received packet is this big it is truncated.
* This is bigger than PeerState.LARGE_MTU, as the far-end's
* LARGE_MTU may be larger than ours.
*/
static final int MAX_PACKET_SIZE = 1536;
public static final int IV_SIZE = 16; public static final int IV_SIZE = 16;
public static final int MAC_SIZE = 16; public static final int MAC_SIZE = 16;
@ -96,7 +102,12 @@ class UDPPacket {
//_dataBuf = _dataCache.acquire(); //_dataBuf = _dataCache.acquire();
Arrays.fill(_data, (byte)0); Arrays.fill(_data, (byte)0);
//_packet = new DatagramPacket(_data, MAX_PACKET_SIZE); //_packet = new DatagramPacket(_data, MAX_PACKET_SIZE);
//_packet.setData(_data); //
// WARNING -
// Doesn't seem like we should have to do this every time,
// from reading the DatagramPacket javadocs,
// but we get massive corruption without it.
_packet.setData(_data);
// _isInbound = inbound; // _isInbound = inbound;
_initializeTime = _context.clock().now(); _initializeTime = _context.clock().now();
_markedType = -1; _markedType = -1;

View File

@ -354,7 +354,9 @@ class UDPPacketReader {
off++; // fragment info off++; // fragment info
return ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF; return ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF;
} }
public void readMessageFragment(int fragmentNum, byte target[], int targetOffset) {
public void readMessageFragment(int fragmentNum, byte target[], int targetOffset)
throws ArrayIndexOutOfBoundsException {
int off = getFragmentBegin(fragmentNum); int off = getFragmentBegin(fragmentNum);
off += 4; // messageId off += 4; // messageId
off++; // fragment info off++; // fragment info

View File

@ -243,6 +243,10 @@ class UDPReceiver {
// and block after we know how much we read but before // and block after we know how much we read but before
// we release the packet to the inbound queue // we release the packet to the inbound queue
if (size >= UDPPacket.MAX_PACKET_SIZE) {
// DatagramSocket javadocs: If the message is longer than the packet's length, the message is truncated.
throw new IOException("packet too large! truncated and dropped");
}
if (size > 0) { if (size > 0) {
//FIFOBandwidthLimiter.Request req = _context.bandwidthLimiter().requestInbound(size, "UDP receiver"); //FIFOBandwidthLimiter.Request req = _context.bandwidthLimiter().requestInbound(size, "UDP receiver");
//_context.bandwidthLimiter().requestInbound(req, size, "UDP receiver"); //_context.bandwidthLimiter().requestInbound(req, size, "UDP receiver");