Changeset 3bd641a


Ignore:
Timestamp:
Dec 6, 2011 9:50:33 PM (8 years ago)
Author:
zzz <zzz@…>
Branches:
master
Children:
258effc
Parents:
be1d95e
Message:
  • UDP: Fix major MTU bug introduced in 0.8.9.
    • Change large MTU from 1492 to 1484 and small from 608 to 620 for encryption padding efficiency
    • Enforce sent MTU limit
    • Increase receive buffer size from 1536 to 1572 so that excessive-sized packets sent by 0.8.9-0.8.11 routers aren't dropped
    • Limit the max acks in a data packet
    • Limit the duplicate acks in successive data packets
    • Only include acks that will fit in the mtu in a data packet
    • Correctly remove acks from the pending set after they are sent, so they aren't sent repeatedly
    • Don't pad data packets unless necessary
    • Debug logging and javadocs
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • history.txt

    rbe1d95e r3bd641a  
     12011-12-06 zzz
     2  * Router:
     3    - More refactoring tasks to their own files
     4    - Adjust some thread priorities
     5  * Susimail: Adjust login form sizes
     6  * Tunnels: Increase next hop send timeout
     7  * UDP: Fix major MTU bug introduced in 0.8.9.
     8    - Change large MTU from 1492 to 1484 and small from 608 to 620
     9      for encryption padding efficiency
     10    - Enforce sent MTU limit
     11    - Increase receive buffer size from 1536 to 1572 so that excessive-sized
     12      packets sent by 0.8.9-0.8.11 routers aren't dropped
     13    - Limit the max acks in a data packet
     14    - Limit the duplicate acks in successive data packets
     15    - Only include acks that will fit in the mtu in a data packet
     16    - Correctly remove acks from the pending set after they are sent,
     17      so they aren't sent repeatedly
     18    - Don't pad data packets unless necessary
     19    - Debug logging and javadocs
     20
    1212011-12-04 zzz
    222  * Console:
  • router/java/src/net/i2p/router/RouterVersion.java

    rbe1d95e r3bd641a  
    1919    public final static String ID = "Monotone";
    2020    public final static String VERSION = CoreVersion.VERSION;
    21     public final static long BUILD = 16;
     21    public final static long BUILD = 17;
    2222
    2323    /** for example "-test" */
  • router/java/src/net/i2p/router/transport/udp/ACKSender.java

    rbe1d95e r3bd641a  
    162162                }
    163163               
    164                 if ( (ackBitfields != null) && (!ackBitfields.isEmpty()) ) {
     164                if (!ackBitfields.isEmpty()) {
    165165                    _context.statManager().addRateData("udp.sendACKCount", ackBitfields.size(), 0);
    166166                    if (remaining > 0)
  • router/java/src/net/i2p/router/transport/udp/InboundMessageState.java

    rbe1d95e r3bd641a  
    154154    }
    155155   
     156    /**
     157     *  A true partial bitfield that is not complete.
     158     */
    156159    private static final class PartialBitfield implements ACKBitfield {
    157         private long _bitfieldMessageId;
    158         private boolean _fragmentsReceived[];
     160        private final long _bitfieldMessageId;
     161        private final boolean _fragmentsReceived[];
    159162       
     163        /**
     164         *  @param data each element is non-null or null for received or not
     165         */
    160166        public PartialBitfield(long messageId, Object data[]) {
    161167            _bitfieldMessageId = messageId;
     168            boolean fragmentsRcvd[] = null;
    162169            for (int i = data.length - 1; i >= 0; i--) {
    163170                if (data[i] != null) {
    164                     if (_fragmentsReceived == null)
    165                         _fragmentsReceived = new boolean[i+1];
    166                     _fragmentsReceived[i] = true;
     171                    if (fragmentsRcvd == null)
     172                        fragmentsRcvd = new boolean[i+1];
     173                    fragmentsRcvd[i] = true;
    167174                }
    168175            }
    169             if (_fragmentsReceived == null)
     176            if (fragmentsRcvd == null)
    170177                _fragmentsReceived = new boolean[0];
    171         }
     178            else
     179                _fragmentsReceived = fragmentsRcvd;
     180        }
     181
    172182        public int fragmentCount() { return _fragmentsReceived.length; }
     183
    173184        public long getMessageId() { return _bitfieldMessageId; }
     185
    174186        public boolean received(int fragmentNum) {
    175187            if ( (fragmentNum < 0) || (fragmentNum >= _fragmentsReceived.length) )
     
    177189            return _fragmentsReceived[fragmentNum];
    178190        }
     191
     192        /** @return false always */
    179193        public boolean receivedComplete() { return false; }
    180194       
  • router/java/src/net/i2p/router/transport/udp/OutboundMessageFragments.java

    rbe1d95e r3bd641a  
    373373            // ok, simplest possible thing is to always tack on the bitfields if
    374374            List<Long> msgIds = peer.getCurrentFullACKs();
    375             if (msgIds == null) msgIds = new ArrayList();
    376375            List<ACKBitfield> partialACKBitfields = new ArrayList();
    377376            peer.fetchPartialACKs(partialACKBitfields);
    378377            int piggybackedPartialACK = partialACKBitfields.size();
    379378            // getCurrentFullACKs() already makes a copy, do we need to copy again?
     379            // YES because buildPacket() now removes them (maybe)
    380380            List<Long> remaining = new ArrayList(msgIds);
    381381            int sparseCount = 0;
  • router/java/src/net/i2p/router/transport/udp/PacketBuilder.java

    rbe1d95e r3bd641a  
    55import java.util.Arrays;
    66import java.util.Collections;
     7import java.util.Iterator;
    78import java.util.List;
    89
     
    125126    static final int PROTOCOL_VERSION = 0;
    126127   
     128    /** if no extended options or rekey data, which we don't support  = 37 */
     129    public static final int HEADER_SIZE = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE + 1 + 4;
     130
     131    /** not including acks. 46 */
     132    public static final int DATA_HEADER_SIZE = HEADER_SIZE + 9;
     133
     134    /** IPv4 only */
     135    public static final int IP_HEADER_SIZE = 20;
     136    public static final int UDP_HEADER_SIZE = 8;
     137
     138    /** 74 */
     139    public static final int MIN_DATA_PACKET_OVERHEAD = IP_HEADER_SIZE + UDP_HEADER_SIZE + DATA_HEADER_SIZE;
     140
     141    /**
     142     *  Only for data packets. No limit in ack-only packets.
     143     *  This directly affects data packet overhead.
     144     */
     145    private static final int MAX_EXPLICIT_ACKS_LARGE = 9;
     146
     147    /**
     148     *  Only for data packets. No limit in ack-only packets.
     149     *  This directly affects data packet overhead.
     150     */
     151    private static final int MAX_EXPLICIT_ACKS_SMALL = 4;
     152
    127153    public PacketBuilder(I2PAppContext ctx, UDPTransport transport) {
    128154        _context = ctx;
     
    143169     * See the methods below for the other message types.
    144170     *
     171     * Note that while the UDP message spec allows for more than one fragment in a message,
     172     * this method writes exactly one fragment.
     173     * For no fragments use buildAck().
     174     * Multiple fragments in a single packet is not supported.
     175     * Rekeying and extended options are not supported.
     176     *
     177     * Packet format:
     178     *<pre>
     179     *    16 byte MAC
     180     *    16 byte IV
     181     *     1 byte flag
     182     *     4 byte date
     183     *     1 byte flag
     184     *     1 byte explicit ack count IF included
     185     *   4*n byte explict acks IF included
     186     *     1 byte ack bitfield count IF included
     187     *   4*n + ?? ack bitfields IF included
     188     *     1 byte fragment count (always 1)
     189     *     4 byte message ID
     190     *     3 byte fragment info
     191     *     n byte fragment
     192     *  0-15 bytes padding
     193     *</pre>
     194     *
     195     * So ignoring the ack bitfields, and assuming we have explicit acks,
     196     * it's (47 + 4*explict acks + padding) added to the
     197     * fragment length.
     198     *
    145199     * @param ackIdsRemaining list of messageIds (Long) that should be acked by this packet. 
    146200     *                        The list itself is passed by reference, and if a messageId is
    147      *                        transmitted and the sender does not want the ID to be included
    148      *                        in subsequent acks, it should be removed from the list.  NOTE:
    149      *                        right now this does NOT remove the IDs, which means it assumes
    150      *                        that the IDs will be transmitted potentially multiple times,
    151      *                        and should otherwise be removed from the list.
     201     *                        transmitted it will be removed from the list.
     202     *                        Not all message IDs will necessarily be sent, there may not be room.
     203     *                        non-null.
     204     *
    152205     * @param partialACKsRemaining list of messageIds (ACKBitfield) that should be acked by this packet. 
    153206     *                        The list itself is passed by reference, and if a messageId is
    154207     *                        included, it should be removed from the list.
    155      */
    156     public UDPPacket buildPacket(OutboundMessageState state, int fragment, PeerState peer, List<Long> ackIdsRemaining, List<ACKBitfield> partialACKsRemaining) {
     208     *                        Full acks in this list are skipped, they are NOT transmitted.
     209     *                        non-null.
     210     *                        Not all acks will necessarily be sent, there may not be room.
     211     *
     212     * @return null on error
     213     */
     214    public UDPPacket buildPacket(OutboundMessageState state, int fragment, PeerState peer,
     215                                 List<Long> ackIdsRemaining, List<ACKBitfield> partialACKsRemaining) {
    157216        UDPPacket packet = buildPacketHeader((byte)(UDPPacket.PAYLOAD_TYPE_DATA << 4));
    158217        byte data[] = packet.getPacket().getData();
     
    163222        if (_log.shouldLog(Log.INFO)) {
    164223            msg = new StringBuilder(128);
    165             msg.append("Send to ").append(peer.getRemotePeer().toBase64());
    166             msg.append(" msg ").append(state.getMessageId()).append(":").append(fragment);
    167             if (fragment == state.getFragmentCount() - 1)
    168                 msg.append("*");
    169         }
    170        
     224            msg.append("Data pkt to ").append(peer.getRemotePeer().toBase64());
     225            msg.append(" msg ").append(state.getMessageId()).append(" frag:").append(fragment);
     226            msg.append('/').append(state.getFragmentCount());
     227        }
     228       
     229        int dataSize = state.fragmentSize(fragment);
     230        if (dataSize < 0) {
     231            packet.release();
     232            return null;
     233        }
     234        int currentMTU = peer.getMTU();
     235        int availableForAcks = currentMTU - MIN_DATA_PACKET_OVERHEAD - dataSize;
     236        int availableForExplicitAcks = availableForAcks;
     237
    171238        // ok, now for the body...
    172239       
    173240        // just always ask for an ACK for now...
    174241        data[off] |= UDPPacket.DATA_FLAG_WANT_REPLY;
    175         // we should in theory only include explicit ACKs if the expected packet size
    176         // is under the MTU, but for now, since the # of packets acked is so few (usually
    177         // just one or two), and since the packets are so small anyway, an additional five
    178         // or ten bytes doesn't hurt.
    179         if ( (ackIdsRemaining != null) && (!ackIdsRemaining.isEmpty()) )
     242
     243        // partial acks have priority but they are after explicit acks in the packet
     244        // so we have to compute the space in advance
     245        int partialAcksToSend = 0;
     246        if (availableForExplicitAcks >= 6 && !partialACKsRemaining.isEmpty()) {
     247            for (ACKBitfield bf : partialACKsRemaining) {
     248                if (bf.receivedComplete())
     249                    continue;
     250                int acksz = 4 + (bf.fragmentCount() / 7) + 1;
     251                if (partialAcksToSend == 0)
     252                    acksz++;  // ack count
     253                if (availableForExplicitAcks >= acksz) {
     254                    availableForExplicitAcks -= acksz;
     255                    partialAcksToSend++;
     256                } else {
     257                    break;
     258                }
     259            }
     260            if (partialAcksToSend > 0)
     261                data[off] |= UDPPacket.DATA_FLAG_ACK_BITFIELDS;
     262        }
     263
     264
     265        // Only include acks if we have at least 5 bytes available and at least
     266        // one ack is requested.
     267        if (availableForExplicitAcks >= 5 && !ackIdsRemaining.isEmpty()) {
    180268            data[off] |= UDPPacket.DATA_FLAG_EXPLICIT_ACK;
    181         if ( (partialACKsRemaining != null) && (!partialACKsRemaining.isEmpty()) )
    182             data[off] |= UDPPacket.DATA_FLAG_ACK_BITFIELDS;
    183         off++;
    184 
    185         if ( (ackIdsRemaining != null) && (!ackIdsRemaining.isEmpty()) ) {
    186             DataHelper.toLong(data, off, 1, ackIdsRemaining.size());
     269        }
     270        off++;
     271
     272        if (msg != null) {
     273            msg.append(" data: ").append(dataSize).append(" bytes, mtu: ")
     274               .append(currentMTU).append(", ")
     275               .append(ackIdsRemaining.size()).append(" full acks requested, ")
     276               .append(partialACKsRemaining.size()).append(" partial acks requested, ")
     277               .append(availableForAcks).append(" avail. for all acks, ")
     278               .append(availableForExplicitAcks).append(" for full acks, ");
     279        }
     280
     281        int explicitToSend = Math.min(currentMTU > PeerState.MIN_MTU ? MAX_EXPLICIT_ACKS_LARGE : MAX_EXPLICIT_ACKS_SMALL,
     282                                      Math.min((availableForExplicitAcks - 1) / 4, ackIdsRemaining.size()));
     283        if (explicitToSend > 0) {
     284            if (msg != null)
     285                msg.append(explicitToSend).append(" full acks included:");
     286            DataHelper.toLong(data, off, 1, explicitToSend);
    187287            off++;
    188             for (int i = 0; i < ackIdsRemaining.size(); i++) {
    189             //while (ackIdsRemaining.size() > 0) {
    190                 Long ackId = ackIdsRemaining.get(i);//(Long)ackIdsRemaining.remove(0);
     288            Iterator<Long> iter = ackIdsRemaining.iterator();
     289            for (int i = 0; i < explicitToSend && iter.hasNext(); i++) {
     290                Long ackId = iter.next();
     291                iter.remove();
    191292                // NPE here, how did a null get in the List?
    192293                DataHelper.toLong(data, off, 4, ackId.longValue());
     
    194295                if (msg != null) // logging it
    195296                    msg.append(" full ack: ").append(ackId.longValue());
    196                 acksIncluded = true;
    197297            }
    198         }
    199 
    200         if ( (partialACKsRemaining != null) && (!partialACKsRemaining.isEmpty()) ) {
     298            //acksIncluded = true;
     299        }
     300
     301        if (partialAcksToSend > 0) {
     302            if (msg != null)
     303                msg.append(partialAcksToSend).append(" partial acks included:");
    201304            int origNumRemaining = partialACKsRemaining.size();
    202305            int numPartialOffset = off;
    203306            // leave it blank for now, since we could skip some
    204307            off++;
    205             for (int i = 0; i < partialACKsRemaining.size(); i++) {
    206                 ACKBitfield bitfield = partialACKsRemaining.get(i);
     308            Iterator<ACKBitfield> iter = partialACKsRemaining.iterator();
     309            for (int i = 0; i < partialAcksToSend && iter.hasNext(); i++) {
     310                ACKBitfield bitfield = iter.next();
    207311                if (bitfield.receivedComplete()) continue;
    208312                DataHelper.toLong(data, off, 4, bitfield.getMessageId());
     
    220324                    off++;
    221325                }
    222                 partialACKsRemaining.remove(i);
     326                iter.remove();
    223327                if (msg != null) // logging it
    224328                    msg.append(" partial ack: ").append(bitfield);
    225                 acksIncluded = true;
    226                 i--;
    227329            }
     330            //acksIncluded = true;
    228331            // now jump back and fill in the number of bitfields *actually* included
    229332            DataHelper.toLong(data, numPartialOffset, 1, origNumRemaining - partialACKsRemaining.size());
    230333        }
    231334       
    232         if ( (msg != null) && (acksIncluded) )
    233             _log.debug(msg.toString());
     335        //if ( (msg != null) && (acksIncluded) )
     336        //  _log.debug(msg.toString());
    234337       
    235338        DataHelper.toLong(data, off, 1, 1); // only one fragment in this message
     
    244347        off++;
    245348       
    246         int size = state.fragmentSize(fragment);
    247         if (size < 0) {
    248             packet.release();
    249             return null;
    250         }
    251         DataHelper.toLong(data, off, 2, size);
     349        DataHelper.toLong(data, off, 2, dataSize);
    252350        data[off] &= (byte)0x3F; // 2 highest bits are reserved
    253351        off += 2;
    254352       
    255353        int sizeWritten = state.writeFragment(data, off, fragment);
    256         if (sizeWritten != size) {
     354        if (sizeWritten != dataSize) {
    257355            if (sizeWritten < 0) {
    258356                // probably already freed from OutboundMessageState
     
    260358                    _log.warn("Write failed for fragment " + fragment + " of " + state.getMessageId());
    261359            } else {
    262                 _log.error("Size written: " + sizeWritten + " but size: " + size
     360                _log.error("Size written: " + sizeWritten + " but size: " + dataSize
    263361                           + " for fragment " + fragment + " of " + state.getMessageId());
    264362            }
    265363            packet.release();
    266364            return null;
    267         } else if (_log.shouldLog(Log.DEBUG))
    268             _log.debug("Size written: " + sizeWritten + " for fragment " + fragment
    269                        + " of " + state.getMessageId());
    270         size = sizeWritten;
    271         if (size < 0) {
    272             packet.release();
    273             return null;
    274         }
    275         off += size;
    276 
    277         // we can pad here if we want, maybe randomized?
     365        //} else if (_log.shouldLog(Log.DEBUG)) {
     366        //    _log.debug("Size written: " + sizeWritten + " for fragment " + fragment
     367        //               + " of " + state.getMessageId());
     368        }
     369        off += dataSize;
     370
    278371       
    279372        // pad up so we're on the encryption boundary
    280         int padSize = 16 - (off % 16);
    281         if (padSize > 0) {
     373        // we could do additional random padding here if desired
     374        int mod = off % 16;
     375        if (mod > 0) {
     376            int padSize = 16 - mod;
    282377            _context.random().nextBytes(data, off, padSize);
    283378            off += padSize;
    284379        }
    285380        packet.getPacket().setLength(off);
     381
    286382        authenticate(packet, peer.getCurrentCipherKey(), peer.getCurrentMACKey());
    287383        setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort());
    288384       
    289385        if (_log.shouldLog(Log.INFO)) {
     386            msg.append(" pkt size ").append(off + (IP_HEADER_SIZE + UDP_HEADER_SIZE));
    290387            _log.info(msg.toString());
    291388        }
    292        
    293         return packet;
    294     }
    295    
    296     /**
     389        // the packet could have been built before the current mtu got lowered, so
     390        // compare to LARGE_MTU
     391        if (off + (IP_HEADER_SIZE + UDP_HEADER_SIZE) > PeerState.LARGE_MTU) {
     392            _log.error("Size is " + off + " for " + packet +
     393                       " fragment " + fragment +
     394                       " data size " + dataSize +
     395                       " pkt size " + (off + (IP_HEADER_SIZE + UDP_HEADER_SIZE)) +
     396                       " MTU " + currentMTU +
     397                       ' ' + availableForAcks + " for all acks " +
     398                       availableForExplicitAcks + " for full acks " +
     399                       explicitToSend + " full acks included " +
     400                       partialAcksToSend + " partial acks included " +
     401                       " OMS " + state, new Exception());
     402        }
     403       
     404        return packet;
     405    }
     406   
     407    /**
     408     * An ACK packet with no acks.
    297409     * We use this for keepalive purposes.
    298410     * It doesn't generate a reply, but that's ok.
     
    308420     *  this method will put all fulls before the partials in the outgoing packet.
    309421     *  An ack packet is just a data packet with no data.
     422     *  See buildPacket() for format.
    310423     *
    311424     * @param ackBitfields list of ACKBitfield instances to either fully or partially ACK
     
    9041017        DataHelper.toLong(data, off, 1, 0);
    9051018        off++;
    906         off += 0; // *cough*
     1019        //off += 0; // *cough*
    9071020       
    9081021        System.arraycopy(ourIntroKey.getData(), 0, data, off, SessionKey.KEYSIZE_BYTES);
     
    10601173    }
    10611174   
    1062     /** if no extended options or rekey data, which we don't support */
    1063     private static final int HEADER_SIZE = UDPPacket.MAC_SIZE + UDPPacket.IV_SIZE + 1 + 4;
    1064 
    10651175    /**
    10661176     *  Create a new packet and add the flag byte and the time stamp.
  • router/java/src/net/i2p/router/transport/udp/PeerState.java

    rbe1d95e r3bd641a  
    217217    private static final int MINIMUM_WINDOW_BYTES = DEFAULT_SEND_WINDOW_BYTES;
    218218    private static final int MAX_SEND_WINDOW_BYTES = 1024*1024;
     219
    219220    /*
    220221     * 596 gives us 588 IP byes, 568 UDP bytes, and with an SSU data message,
     
    229230     * We reduce the max acks when using the small MTU but it may not be enough...
    230231     *
    231      */
    232     private static final int MIN_MTU = 608;//600; //1500;
     232     * Goal: VTBM msg fragments 2646 / (620 - 87) fits nicely.
     233     *
     234     * Assuming that we can enforce an MTU correctly, this % 16 should be 12,
     235     * as the IP/UDP header is 28 bytes and data max should be mulitple of 16 for padding efficiency,
     236     * and so PacketBuilder.buildPacket() works correctly.
     237     */
     238    public static final int MIN_MTU = 620;
    233239    private static final int DEFAULT_MTU = MIN_MTU;
     240
    234241    /*
    235242     * based on measurements, 1350 fits nearly all reasonably small I2NP messages
     
    242249     * 1323 + 74 + 46 + 1 + (4 * 9) = 1480
    243250     * So why not make it 1492 (old ethernet is 1492, new is 1500)
    244      */
    245     private static final int LARGE_MTU = 1492;
     251     * Changed to 1492 in 0.8.9
     252     *
     253     * BUT through 0.8.11,
     254     * size estimate was bad, actual packet was up to 48 bytes bigger
     255     * To be figured out. Curse the ACKs.
     256     * Assuming that we can enforce an MTU correctly, this % 16 should be 12,
     257     * as the IP/UDP header is 28 bytes and data max should be mulitple of 16 for padding efficiency,
     258     * and so PacketBuilder.buildPacket() works correctly.
     259     */
     260    public static final int LARGE_MTU = 1484;
    246261   
    247262    private static final int MIN_RTO = 100 + ACKSender.ACK_FREQUENCY;
     
    700715     * removeACKMessage(Long) should be called.
    701716     *
     717     * The returned list contains acks not yet sent, followed by
     718     * a random assortment of acks already sent.
     719     * The caller should NOT transmit all of them all the time,
     720     * even if there is room,
     721     * or the packets will have way too much overhead.
     722     *
     723     * @return a new list, do as you like with it
    702724     */
    703725    public List<Long> getCurrentFullACKs() {
    704726            // no such element exception seen here
    705             ArrayList<Long> rv = new ArrayList(_currentACKs);
     727            List<Long> rv = new ArrayList(_currentACKs);
    706728            // include some for retransmission
    707             rv.addAll(_currentACKsResend);
     729            List<Long> randomResends = new ArrayList(_currentACKsResend);
     730            Collections.shuffle(randomResends, _context.random());
     731            rv.addAll(randomResends);
     732            if (_log.shouldLog(Log.INFO))
     733                _log.info("Returning " + _currentACKs.size() + " current and " + randomResends.size() + " resend acks");
    708734            return rv;
    709735    }
    710736
     737    /** the ack was sent */
    711738    public void removeACKMessage(Long messageId) {
    712             _currentACKs.remove(messageId);
    713             _currentACKsResend.offer(messageId);
    714             // trim down the resends
    715             while (_currentACKsResend.size() > MAX_RESEND_ACKS)
    716                 _currentACKsResend.poll();
     739            boolean removed = _currentACKs.remove(messageId);
     740            if (removed) {
     741                // only add if reoved from current, as this may be called for
     742                // acks already in _currentACKsResend.
     743                _currentACKsResend.offer(messageId);
     744                // trim down the resends
     745                while (_currentACKsResend.size() > MAX_RESEND_ACKS)
     746                    _currentACKsResend.poll();
     747                if (_log.shouldLog(Log.INFO))
     748                    _log.info("Sent ack " + messageId + " now " + _currentACKs.size() + " current and " +
     749                              _currentACKsResend.size() + " resend acks");
     750            }
     751            // should we only do this if removed?
    717752            _lastACKSend = _context.clock().now();
    718753    }
     
    723758    private static final int MAX_RESEND_ACKS = 16;
    724759    /**
    725      *  The number of duplicate acks sent in each messge -
    726      *  Warning, this directly affects network overhead
    727      *  Was 16 but that's too much (64 bytes in a max 608 byte packet,
    728      *  and often much smaller)
     760     *  The max number of duplicate acks sent in each ack-only messge.
     761     *  Doesn't really matter, we have plenty of room...
    729762     *  @since 0.7.13
    730763     */
    731     private static final int MAX_RESEND_ACKS_LARGE = 9;
     764    private static final int MAX_RESEND_ACKS_LARGE = MAX_RESEND_ACKS;
    732765    /** for small MTU */
    733     private static final int MAX_RESEND_ACKS_SMALL = 4;
     766    private static final int MAX_RESEND_ACKS_SMALL = MAX_RESEND_ACKS;
    734767   
    735768    /**
     
    741774     * will be unchanged if there are ACKs remaining.
    742775     *
     776     * @return non-null, possibly empty
     777     * @deprecated unused
    743778     */
    744779    public List<ACKBitfield> retrieveACKBitfields() { return retrieveACKBitfields(true); }
    745780
     781    /**
     782     * See above. Only called by ACKSender with alwaysIncludeRetransmissions = false.
     783     * So this is only for ACK-only packets, so all the size limiting is useless.
     784     * FIXME.
     785     *
     786     * @return non-null, possibly empty
     787     */
    746788    public List<ACKBitfield> retrieveACKBitfields(boolean alwaysIncludeRetransmissions) {
    747789        List<ACKBitfield> rv = new ArrayList(MAX_RESEND_ACKS);
     
    822864
    823865        _lastACKSend = _context.clock().now();
    824         if (rv == null)
    825             rv = Collections.EMPTY_LIST;
     866        //if (rv == null)
     867        //    rv = Collections.EMPTY_LIST;
    826868        if (partialIncluded > 0)
    827869            _context.statManager().addRateData("udp.sendACKPartial", partialIncluded, rv.size() - partialIncluded);
     
    829871    }
    830872   
     873    /**
     874     *  @param rv out parameter, populated with true partial ACKBitfields.
     875     *            no full bitfields are included.
     876     */
    831877    void fetchPartialACKs(List<ACKBitfield> rv) {
    832878        InboundMessageState states[] = null;
     
    854900        }
    855901        if (states != null) {
     902            // _inboundMessages is a Map (unordered), so why bother going backwards?
    856903            for (int i = curState-1; i >= 0; i--) {
    857904                if (states[i] != null)
     
    861908    }
    862909   
    863     /** represent a full ACK of a message */
     910    /**
     911     *  A dummy "partial" ack which represents a full ACK of a message
     912     */
    864913    private static class FullACKBitfield implements ACKBitfield {
    865         private long _msgId;
     914        private final long _msgId;
     915
    866916        public FullACKBitfield(long id) { _msgId = id; }
     917
    867918        public int fragmentCount() { return 0; }
    868919        public long getMessageId() { return _msgId; }
     
    10631114    public void setLastACKSend(long when) { _lastACKSend = when; }
    10641115    public long getWantedACKSendSince() { return _wantACKSendSince; }
     1116
    10651117    public boolean unsentACKThresholdReached() {
    10661118        int threshold = countMaxACKData() / 4;
     
    10711123    private int countMaxACKData() {
    10721124        return _mtu
    1073                 - IP_HEADER_SIZE
    1074                 - UDP_HEADER_SIZE
     1125                - PacketBuilder.IP_HEADER_SIZE
     1126                - PacketBuilder.UDP_HEADER_SIZE
    10751127                - UDPPacket.IV_SIZE
    10761128                - UDPPacket.MAC_SIZE
     
    13361388    private static final boolean THROTTLE_INITIAL_SEND = true;
    13371389   
    1338     private static final int SSU_HEADER_SIZE = 46;
    1339     static final int UDP_HEADER_SIZE = 8;
    1340     static final int IP_HEADER_SIZE = 20;
     1390    /**
     1391     *  Always leave room for this many explicit acks.
     1392     *  Only for data packets. Does not affect ack-only packets.
     1393     *  This directly affects data packet overhead, adjust with care.
     1394     */
     1395    private static final int MIN_EXPLICIT_ACKS = 3;
     1396    /** this is room for three explicit acks or two partial acks or one of each = 13 */
     1397    private static final int MIN_ACK_SIZE = 1 + (4 * MIN_EXPLICIT_ACKS);
    13411398
    13421399    /**
    13431400     *  how much payload data can we shove in there?
    1344      *  @return MTU - 74
     1401     *  @return MTU - 87, i.e. 521 or 1401
    13451402     */
    13461403    private static final int fragmentSize(int mtu) {
    1347         return mtu - SSU_HEADER_SIZE - UDP_HEADER_SIZE - IP_HEADER_SIZE;
     1404        // 46 + 20 + 8 + 13 = 74 + 13 = 87
     1405        return mtu - (PacketBuilder.MIN_DATA_PACKET_OVERHEAD + MIN_ACK_SIZE);
    13481406    }
    13491407   
  • router/java/src/net/i2p/router/transport/udp/UDPPacket.java

    rbe1d95e r3bd641a  
    5757     *  This is bigger than PeerState.LARGE_MTU, as the far-end's
    5858     *  LARGE_MTU may be larger than ours.
    59      */
    60     static final int MAX_PACKET_SIZE = 1536;
     59     *
     60     *  Due to longstanding bugs, a packet may be larger than LARGE_MTU
     61     *  (acks and padding). Together with an increase in the LARGE_MTU to
     62     *  1492 in release 0.8.9, routers from 0.8.9 - 0.8.11 can generate
     63     *  packets up to 1536. Data packets are always a multiple of 16,
     64     *  so make this 4 + a multiple of 16.
     65     */
     66    static final int MAX_PACKET_SIZE = 1572;
    6167    public static final int IV_SIZE = 16;
    6268    public static final int MAC_SIZE = 16;
     
    117123    }
    118124   
     125  /****
    119126    public void writeData(byte src[], int offset, int len) {
    120127        verifyNotReleased();
     
    123130        resetBegin();
    124131    }
     132  ****/
     133
     134    /** */
    125135    public DatagramPacket getPacket() { verifyNotReleased(); return _packet; }
    126136    public short getPriority() { verifyNotReleased(); return _priority; }
     
    264274        buf.append(_packet.getAddress().getHostAddress()).append(":");
    265275        buf.append(_packet.getPort());
    266         buf.append(" id=").append(System.identityHashCode(this));
     276        //buf.append(" id=").append(System.identityHashCode(this));
     277        buf.append(" msg type=").append(_messageType);
     278        buf.append(" mark type=").append(_markedType);
     279        buf.append(" frag count=").append(_fragmentCount);
    267280
    268281        buf.append(" sinceEnqueued=").append((_enqueueTime > 0 ? _context.clock().now()-_enqueueTime : -1));
  • router/java/src/net/i2p/router/transport/udp/UDPSender.java

    rbe1d95e r3bd641a  
    159159        if (packet == null || !_keepRunning) return 0;
    160160        int size = 0;
     161        int psz = packet.getPacket().getLength();
     162        if (psz > PeerState.LARGE_MTU)
     163            _log.error("Sending large UDP packet " + psz + " bytes: " + packet);
    161164        _outboundQueue.offer(packet);
    162165        //size = _outboundQueue.size();
     
    188191                    long acquireTime = _context.clock().now();
    189192                    int size = packet.getPacket().getLength();
    190                     int size2 = packet.getPacket().getLength();
     193                    // ?? int size2 = packet.getPacket().getLength();
    191194                    if (size > 0) {
    192195                        //_context.bandwidthLimiter().requestOutbound(req, size, "UDP sender");
Note: See TracChangeset for help on using the changeset viewer.