java.lang.Object
net.i2p.router.transport.udp.SSU2Bitfield
Container of a long array representing set and unset bits. When a bit higher than the current size + offset is set, the offset shifts up and the lowest set bits are lost.
Also contains methods to convert to/from an ACK block.
Locking: Most methods are synchronized here. Do not call methods with the PeerState2 lock held, chance of deadlock.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic interfaceCallback interface for bitfield operations.Field Summary
FieldsModifier and TypeFieldDescriptionprivate final long[]Bit storage.private intHighest set bit before offset, -1 if none.(package private) static final intLargest message-number span (in bits) we will build from a received ACK block.private final intMaximum shift.private final intMinimum shift.private longCurrent offset.private final intBitfield size.Constructor Summary
ConstructorsConstructorDescriptionSSU2Bitfield(int size, long offset) Creates a new SSU2Bitfield that representssizeunset bits.Method Summary
Modifier and TypeMethodDescription(package private) static longcalculateAckSpan(int thru, int acnt, byte[] ranges, int rangeCount) Compute the number of message numbers (bits) the bitfield for an ACK block must cover, without allocating one.voidCallback for all bits set in this bitfield but not set in bf2.static SSU2BitfieldfromACKBlock(long thru, int acnt, byte[] ranges, int rangeCount) Rebuild a bitfield from a received ACK block, rejecting a block whose implied span would push the offset below zero or exceedMAX_ACK_SPAN.booleanget(long bit) Return true if the bit is set or false if it is not.longReturn the highest set bit, or -1 if none.longThe current offset.booleanset(long bit) Mark the given bit as set.intsize()The size in bits.toAckBlock(int maxRanges) Render the set bits as an ACK block, collapsing the top acnt bits into the ACK count and the rest into at most maxRanges ranges.toString()String representation of this bitfield.static StringtoString(long thru, int acnt, byte[] ranges, int rangeCount) Pretty print an ACK block.
Field Details
MAX_ACK_SPAN
static final int MAX_ACK_SPANLargest message-number span (in bits) we will build from a received ACK block. A peer's own receive bitfield is 512 bits and shifts up by at most max_shift (4096) before starting over, so a live peer can legitimately describe a span of under 512 + 4096 bits. Anything beyond that is a malformed or hostile block: the span is derived from unvalidated attacker-controlled bytes, so an unchecked value lets a ~1.5KB packet allocate a ~48KB bitfield. The margin here leaves room for implementation differences while capping the allocation at 1KB.- See Also:
bitfield
private final long[] bitfieldBit storage.size
private final int sizeBitfield size.max_shift
private final int max_shiftMaximum shift.min_shift
private final int min_shiftMinimum shift.offset
private long offsetCurrent offset.highestSet
private int highestSetHighest set bit before offset, -1 if none.
Constructor Details
SSU2Bitfield
public SSU2Bitfield(int size, long offset) Creates a new SSU2Bitfield that representssizeunset bits.- Parameters:
size- the bitfield width in bits, rounded up to a multiple of 256offset- the message number the first bit represents, non-negative
Method Details
size
public int size()The size in bits.- Returns:
- the bitfield width in bits
getOffset
public long getOffset()The current offset.- Returns:
- the message number the lowest bit represents
set
Mark the given bit as set. When a bit higher than the current size + offset is set, the offset shifts up and the lowest set bits are lost.- Parameters:
bit- the absolute message number to set, non-negative- Returns:
- previous value, true if previously set or unknown
- Throws:
IndexOutOfBoundsException- if bit is smaller then zero OR if the shift is too big
get
public boolean get(long bit) Return true if the bit is set or false if it is not.- Parameters:
bit- the absolute message number to test, non-negative- Returns:
- true if the bit is set, false if unset or already shifted out
- Throws:
IndexOutOfBoundsException- if bit is smaller then zero
getHighestSet
public long getHighestSet()Return the highest set bit, or -1 if none.- Returns:
- the highest set
toAckBlock
Render the set bits as an ACK block, collapsing the top acnt bits into the ACK count and the rest into at most maxRanges ranges.- Parameters:
maxRanges- may be 0- Returns:
- null if nothing is set
calculateAckSpan
static long calculateAckSpan(int thru, int acnt, byte[] ranges, int rangeCount) Compute the number of message numbers (bits) the bitfield for an ACK block must cover, without allocating one.Pure and package-visible so the hostile-input case can be tested directly.
- Parameters:
thru- the highest acked message numberacnt- number of contiguous acks below thru, 0-255ranges- non-null, at least rangeCount * 2 bytesrangeCount- number of (nack, ack) range pairs, must be non-zero- Returns:
- the span in bits, always at least 1
- Throws:
IndexOutOfBoundsException- if ranges is too short for rangeCount
fromACKBlock
Rebuild a bitfield from a received ACK block, rejecting a block whose implied span would push the offset below zero or exceedMAX_ACK_SPAN.- Parameters:
thru- the highest acked message numberacnt- number of contiguous acks below thru, 0-255ranges- may be nullrangeCount- number of (nack, ack) range pairs- Returns:
- a bitfield covering every message the block acks
- Throws:
IllegalArgumentException- if the ranges describe a span larger thanMAX_ACK_SPAN
forEachAndNot
Callback for all bits set in this bitfield but not set in bf2.If this offset is greater than bf2's highest bit set, i.e. this bitfield is completely newer, calls back for all bits in this bitfield.
If this highest bit set is less than than bf2's offset, i.e. this bitfield is completely older, the callback will not be called.
Synchs on this and then on bf2.
Usage: this is the received acks, bf2 is previously acked, callback for each newly acked.
- Parameters:
bf2- the previously acknowledged bitfield, updated in placecb- called once per message newly acked by this bitfield
toString
Pretty print an ACK block.- Parameters:
thru- the highest acked message numberacnt- number of contiguous acks below thru, 0-255ranges- may be nullrangeCount- number of (nack, ack) range pairs- Returns:
- the block as "ACK 1234-1200 NACK 1199 ACK 1198-1190" style text
toString