diff --git a/internal/wire/ack_frame.go b/internal/wire/ack_frame.go index e77bdf1f..5f0bc975 100644 --- a/internal/wire/ack_frame.go +++ b/internal/wire/ack_frame.go @@ -9,340 +9,166 @@ import ( "github.com/lucas-clemente/quic-go/internal/utils" ) -var ( - // ErrInvalidAckRanges occurs when a client sends inconsistent ACK ranges - ErrInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges") - // ErrInvalidFirstAckRange occurs when the first ACK range contains no packets - ErrInvalidFirstAckRange = errors.New("AckFrame: ACK frame has invalid first ACK range") -) +// TODO: use the value sent in the transport parameters +const ackDelayExponent = 3 -var ( - errInconsistentAckLargestAcked = errors.New("internal inconsistency: LargestAcked does not match ACK ranges") - errInconsistentAckLowestAcked = errors.New("internal inconsistency: LowestAcked does not match ACK ranges") -) - -// An AckFrame is an ACK frame in QUIC +// An AckFrame is an ACK frame type AckFrame struct { LargestAcked protocol.PacketNumber LowestAcked protocol.PacketNumber AckRanges []AckRange // has to be ordered. The highest ACK range goes first, the lowest ACK range goes last // time when the LargestAcked was receiveid - // this field Will not be set for received ACKs frames + // this field will not be set for received ACKs frames PacketReceivedTime time.Time DelayTime time.Duration } // ParseAckFrame reads an ACK frame func ParseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { - frame := &AckFrame{} + if !version.UsesIETFFrameFormat() { + return parseAckFrameLegacy(r, version) + } - typeByte, err := r.ReadByte() - if err != nil { + if _, err := r.ReadByte(); err != nil { return nil, err } - hasMissingRanges := false - if typeByte&0x20 == 0x20 { - hasMissingRanges = true - } + frame := &AckFrame{} - largestAckedLen := 2 * ((typeByte & 0x0C) >> 2) - if largestAckedLen == 0 { - largestAckedLen = 1 - } - - missingSequenceNumberDeltaLen := 2 * (typeByte & 0x03) - if missingSequenceNumberDeltaLen == 0 { - missingSequenceNumberDeltaLen = 1 - } - - largestAcked, err := utils.GetByteOrder(version).ReadUintN(r, largestAckedLen) + largestAcked, err := utils.ReadVarInt(r) if err != nil { return nil, err } frame.LargestAcked = protocol.PacketNumber(largestAcked) - - delay, err := utils.GetByteOrder(version).ReadUfloat16(r) + delay, err := utils.ReadVarInt(r) + if err != nil { + return nil, err + } + frame.DelayTime = time.Duration(delay*1< frame.LargestAcked { + return nil, errors.New("invalid first ACK range") + } + smallest := frame.LargestAcked - protocol.PacketNumber(ackBlock) + + // read all the other ACK ranges + if numBlocks > 0 { + frame.AckRanges = append(frame.AckRanges, AckRange{First: smallest, Last: frame.LargestAcked}) + } + for i := uint64(0); i < numBlocks; i++ { + g, err := utils.ReadVarInt(r) if err != nil { return nil, err } - } - - if hasMissingRanges && numAckBlocks == 0 { - return nil, ErrInvalidAckRanges - } - - ackBlockLength, err := utils.GetByteOrder(version).ReadUintN(r, missingSequenceNumberDeltaLen) - if err != nil { - return nil, err - } - if frame.LargestAcked > 0 && ackBlockLength < 1 { - return nil, ErrInvalidFirstAckRange - } - - if ackBlockLength > largestAcked+1 { - return nil, ErrInvalidAckRanges - } - - if hasMissingRanges { - ackRange := AckRange{ - First: protocol.PacketNumber(largestAcked-ackBlockLength) + 1, - Last: frame.LargestAcked, + gap := protocol.PacketNumber(g) + if smallest < gap+2 { + return nil, errInvalidAckRanges } - frame.AckRanges = append(frame.AckRanges, ackRange) + largest := smallest - gap - 2 - var inLongBlock bool - var lastRangeComplete bool - for i := uint8(0); i < numAckBlocks; i++ { - var gap uint8 - gap, err = r.ReadByte() - if err != nil { - return nil, err - } - - ackBlockLength, err = utils.GetByteOrder(version).ReadUintN(r, missingSequenceNumberDeltaLen) - if err != nil { - return nil, err - } - - length := protocol.PacketNumber(ackBlockLength) - - if inLongBlock { - frame.AckRanges[len(frame.AckRanges)-1].First -= protocol.PacketNumber(gap) + length - frame.AckRanges[len(frame.AckRanges)-1].Last -= protocol.PacketNumber(gap) - } else { - lastRangeComplete = false - ackRange := AckRange{ - Last: frame.AckRanges[len(frame.AckRanges)-1].First - protocol.PacketNumber(gap) - 1, - } - ackRange.First = ackRange.Last - length + 1 - frame.AckRanges = append(frame.AckRanges, ackRange) - } - - if length > 0 { - lastRangeComplete = true - } - - inLongBlock = (ackBlockLength == 0) + ab, err := utils.ReadVarInt(r) + if err != nil { + return nil, err } + ackBlock := protocol.PacketNumber(ab) - // if the last range was not complete, First and Last make no sense - // remove the range from frame.AckRanges - if !lastRangeComplete { - frame.AckRanges = frame.AckRanges[:len(frame.AckRanges)-1] - } - - frame.LowestAcked = frame.AckRanges[len(frame.AckRanges)-1].First - } else { - if frame.LargestAcked == 0 { - frame.LowestAcked = 0 - } else { - frame.LowestAcked = protocol.PacketNumber(largestAcked + 1 - ackBlockLength) + if ackBlock > largest { + return nil, errInvalidAckRanges } + smallest = largest - protocol.PacketNumber(ackBlock) + frame.AckRanges = append(frame.AckRanges, AckRange{First: smallest, Last: largest}) } + frame.LowestAcked = smallest if !frame.validateAckRanges() { - return nil, ErrInvalidAckRanges + return nil, errInvalidAckRanges } - var numTimestamp byte - numTimestamp, err = r.ReadByte() - if err != nil { - return nil, err - } - - if numTimestamp > 0 { - // Delta Largest acked - _, err = r.ReadByte() - if err != nil { - return nil, err - } - // First Timestamp - _, err = utils.GetByteOrder(version).ReadUint32(r) - if err != nil { - return nil, err - } - - for i := 0; i < int(numTimestamp)-1; i++ { - // Delta Largest acked - _, err = r.ReadByte() - if err != nil { - return nil, err - } - - // Time Since Previous Timestamp - _, err = utils.GetByteOrder(version).ReadUint16(r) - if err != nil { - return nil, err - } - } - } return frame, nil } // Write writes an ACK frame. func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error { - largestAckedLen := protocol.GetPacketNumberLength(f.LargestAcked) - - typeByte := uint8(0x40) - - if largestAckedLen != protocol.PacketNumberLen1 { - typeByte ^= (uint8(largestAckedLen / 2)) << 2 + if !version.UsesIETFFrameFormat() { + return f.writeLegacy(b, version) } - missingSequenceNumberDeltaLen := f.getMissingSequenceNumberDeltaLen() - if missingSequenceNumberDeltaLen != protocol.PacketNumberLen1 { - typeByte ^= (uint8(missingSequenceNumberDeltaLen / 2)) - } + b.WriteByte(0xe) + utils.WriteVarInt(b, uint64(f.LargestAcked)) + utils.WriteVarInt(b, encodeAckDelay(f.DelayTime)) + // TODO: limit the number of ACK ranges, such that the frame doesn't grow larger than an upper bound + var lowestInFirstRange protocol.PacketNumber if f.HasMissingRanges() { - typeByte |= 0x20 - } - - b.WriteByte(typeByte) - - switch largestAckedLen { - case protocol.PacketNumberLen1: - b.WriteByte(uint8(f.LargestAcked)) - case protocol.PacketNumberLen2: - utils.GetByteOrder(version).WriteUint16(b, uint16(f.LargestAcked)) - case protocol.PacketNumberLen4: - utils.GetByteOrder(version).WriteUint32(b, uint32(f.LargestAcked)) - case protocol.PacketNumberLen6: - utils.GetByteOrder(version).WriteUint48(b, uint64(f.LargestAcked)&(1<<48-1)) - } - - f.DelayTime = time.Since(f.PacketReceivedTime) - utils.GetByteOrder(version).WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond)) - - var numRanges uint64 - var numRangesWritten uint64 - if f.HasMissingRanges() { - numRanges = f.numWritableNackRanges() - if numRanges > 0xFF { - panic("AckFrame: Too many ACK ranges") - } - b.WriteByte(uint8(numRanges - 1)) - } - - var firstAckBlockLength protocol.PacketNumber - if !f.HasMissingRanges() { - firstAckBlockLength = f.LargestAcked - f.LowestAcked + 1 + utils.WriteVarInt(b, uint64(len(f.AckRanges)-1)) + lowestInFirstRange = f.AckRanges[0].First } else { - if f.LargestAcked != f.AckRanges[0].Last { - return errInconsistentAckLargestAcked - } - if f.LowestAcked != f.AckRanges[len(f.AckRanges)-1].First { - return errInconsistentAckLowestAcked - } - firstAckBlockLength = f.LargestAcked - f.AckRanges[0].First + 1 - numRangesWritten++ + utils.WriteVarInt(b, 0) + lowestInFirstRange = f.LowestAcked } - switch missingSequenceNumberDeltaLen { - case protocol.PacketNumberLen1: - b.WriteByte(uint8(firstAckBlockLength)) - case protocol.PacketNumberLen2: - utils.GetByteOrder(version).WriteUint16(b, uint16(firstAckBlockLength)) - case protocol.PacketNumberLen4: - utils.GetByteOrder(version).WriteUint32(b, uint32(firstAckBlockLength)) - case protocol.PacketNumberLen6: - utils.GetByteOrder(version).WriteUint48(b, uint64(firstAckBlockLength)&(1<<48-1)) - } + // write the first range + utils.WriteVarInt(b, uint64(f.LargestAcked-lowestInFirstRange)) + // write all the other range + if !f.HasMissingRanges() { + return nil + } + var lowest protocol.PacketNumber for i, ackRange := range f.AckRanges { if i == 0 { + lowest = lowestInFirstRange continue } - - length := ackRange.Last - ackRange.First + 1 - gap := f.AckRanges[i-1].First - ackRange.Last - 1 - - num := gap/0xFF + 1 - if gap%0xFF == 0 { - num-- - } - - if num == 1 { - b.WriteByte(uint8(gap)) - switch missingSequenceNumberDeltaLen { - case protocol.PacketNumberLen1: - b.WriteByte(uint8(length)) - case protocol.PacketNumberLen2: - utils.GetByteOrder(version).WriteUint16(b, uint16(length)) - case protocol.PacketNumberLen4: - utils.GetByteOrder(version).WriteUint32(b, uint32(length)) - case protocol.PacketNumberLen6: - utils.GetByteOrder(version).WriteUint48(b, uint64(length)&(1<<48-1)) - } - numRangesWritten++ - } else { - for i := 0; i < int(num); i++ { - var lengthWritten uint64 - var gapWritten uint8 - - if i == int(num)-1 { // last block - lengthWritten = uint64(length) - gapWritten = uint8(1 + ((gap - 1) % 255)) - } else { - lengthWritten = 0 - gapWritten = 0xFF - } - - b.WriteByte(gapWritten) - switch missingSequenceNumberDeltaLen { - case protocol.PacketNumberLen1: - b.WriteByte(uint8(lengthWritten)) - case protocol.PacketNumberLen2: - utils.GetByteOrder(version).WriteUint16(b, uint16(lengthWritten)) - case protocol.PacketNumberLen4: - utils.GetByteOrder(version).WriteUint32(b, uint32(lengthWritten)) - case protocol.PacketNumberLen6: - utils.GetByteOrder(version).WriteUint48(b, lengthWritten&(1<<48-1)) - } - - numRangesWritten++ - } - } - - // this is needed if not all AckRanges can be written to the ACK frame (if there are more than 0xFF) - if numRangesWritten >= numRanges { - break - } + utils.WriteVarInt(b, uint64(lowest-ackRange.Last-2)) + utils.WriteVarInt(b, uint64(ackRange.Last-ackRange.First)) + lowest = ackRange.First } - - if numRanges != numRangesWritten { - return errors.New("BUG: Inconsistent number of ACK ranges written") - } - - b.WriteByte(0) // no timestamps return nil } // MinLength of a written frame func (f *AckFrame) MinLength(version protocol.VersionNumber) (protocol.ByteCount, error) { - length := protocol.ByteCount(1 + 2 + 1) // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp - length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestAcked)) - - missingSequenceNumberDeltaLen := protocol.ByteCount(f.getMissingSequenceNumberDeltaLen()) - - if f.HasMissingRanges() { - length += (1 + missingSequenceNumberDeltaLen) * protocol.ByteCount(f.numWritableNackRanges()) - } else { - length += missingSequenceNumberDeltaLen + if !version.UsesIETFFrameFormat() { + return f.minLengthLegacy(version) } - length += (1 + 2) * 0 /* TODO: num_timestamps */ + length := 1 + utils.VarIntLen(uint64(f.LargestAcked)) + utils.VarIntLen(uint64(encodeAckDelay(f.DelayTime))) + var lowestInFirstRange protocol.PacketNumber + if f.HasMissingRanges() { + length += utils.VarIntLen(uint64(len(f.AckRanges) - 1)) + lowestInFirstRange = f.AckRanges[0].First + } else { + length += utils.VarIntLen(0) + lowestInFirstRange = f.LowestAcked + } + length += utils.VarIntLen(uint64(f.LargestAcked - lowestInFirstRange)) + + if !f.HasMissingRanges() { + return length, nil + } + var lowest protocol.PacketNumber + for i, ackRange := range f.AckRanges { + if i == 0 { + lowest = ackRange.First + continue + } + length += utils.VarIntLen(uint64(lowest - ackRange.Last - 2)) + length += utils.VarIntLen(uint64(ackRange.Last - ackRange.First)) + lowest = ackRange.First + } return length, nil } @@ -389,63 +215,6 @@ func (f *AckFrame) validateAckRanges() bool { return true } -// numWritableNackRanges calculates the number of ACK blocks that are about to be written -// this number is different from len(f.AckRanges) for the case of long gaps (> 255 packets) -func (f *AckFrame) numWritableNackRanges() uint64 { - if len(f.AckRanges) == 0 { - return 0 - } - - var numRanges uint64 - for i, ackRange := range f.AckRanges { - if i == 0 { - continue - } - - lastAckRange := f.AckRanges[i-1] - gap := lastAckRange.First - ackRange.Last - 1 - rangeLength := 1 + uint64(gap)/0xFF - if uint64(gap)%0xFF == 0 { - rangeLength-- - } - - if numRanges+rangeLength < 0xFF { - numRanges += rangeLength - } else { - break - } - } - - return numRanges + 1 -} - -func (f *AckFrame) getMissingSequenceNumberDeltaLen() protocol.PacketNumberLen { - var maxRangeLength protocol.PacketNumber - - if f.HasMissingRanges() { - for _, ackRange := range f.AckRanges { - rangeLength := ackRange.Last - ackRange.First + 1 - if rangeLength > maxRangeLength { - maxRangeLength = rangeLength - } - } - } else { - maxRangeLength = f.LargestAcked - f.LowestAcked + 1 - } - - if maxRangeLength <= 0xFF { - return protocol.PacketNumberLen1 - } - if maxRangeLength <= 0xFFFF { - return protocol.PacketNumberLen2 - } - if maxRangeLength <= 0xFFFFFFFF { - return protocol.PacketNumberLen4 - } - - return protocol.PacketNumberLen6 -} - // AcksPacket determines if this ACK frame acks a certain packet number func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool { if p < f.LowestAcked || p > f.LargestAcked { // this is just a performance optimization @@ -464,3 +233,7 @@ func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool { // if packet doesn't have missing ranges return (p >= f.LowestAcked && p <= f.LargestAcked) } + +func encodeAckDelay(delay time.Duration) uint64 { + return uint64(delay.Nanoseconds() / (1000 * (1 << ackDelayExponent))) +} diff --git a/internal/wire/ack_frame_legacy.go b/internal/wire/ack_frame_legacy.go new file mode 100644 index 00000000..445f3373 --- /dev/null +++ b/internal/wire/ack_frame_legacy.go @@ -0,0 +1,381 @@ +package wire + +import ( + "bytes" + "errors" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" +) + +var ( + errInconsistentAckLargestAcked = errors.New("internal inconsistency: LargestAcked does not match ACK ranges") + errInconsistentAckLowestAcked = errors.New("internal inconsistency: LowestAcked does not match ACK ranges") + errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges") +) + +func parseAckFrameLegacy(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { + frame := &AckFrame{} + + typeByte, err := r.ReadByte() + if err != nil { + return nil, err + } + + hasMissingRanges := false + if typeByte&0x20 == 0x20 { + hasMissingRanges = true + } + + largestAckedLen := 2 * ((typeByte & 0x0C) >> 2) + if largestAckedLen == 0 { + largestAckedLen = 1 + } + + missingSequenceNumberDeltaLen := 2 * (typeByte & 0x03) + if missingSequenceNumberDeltaLen == 0 { + missingSequenceNumberDeltaLen = 1 + } + + largestAcked, err := utils.GetByteOrder(version).ReadUintN(r, largestAckedLen) + if err != nil { + return nil, err + } + frame.LargestAcked = protocol.PacketNumber(largestAcked) + + delay, err := utils.GetByteOrder(version).ReadUfloat16(r) + if err != nil { + return nil, err + } + frame.DelayTime = time.Duration(delay) * time.Microsecond + + var numAckBlocks uint8 + if hasMissingRanges { + numAckBlocks, err = r.ReadByte() + if err != nil { + return nil, err + } + } + + if hasMissingRanges && numAckBlocks == 0 { + return nil, errInvalidAckRanges + } + + ackBlockLength, err := utils.GetByteOrder(version).ReadUintN(r, missingSequenceNumberDeltaLen) + if err != nil { + return nil, err + } + if frame.LargestAcked > 0 && ackBlockLength < 1 { + return nil, errors.New("invalid first ACK range") + } + + if ackBlockLength > largestAcked+1 { + return nil, errInvalidAckRanges + } + + if hasMissingRanges { + ackRange := AckRange{ + First: protocol.PacketNumber(largestAcked-ackBlockLength) + 1, + Last: frame.LargestAcked, + } + frame.AckRanges = append(frame.AckRanges, ackRange) + + var inLongBlock bool + var lastRangeComplete bool + for i := uint8(0); i < numAckBlocks; i++ { + var gap uint8 + gap, err = r.ReadByte() + if err != nil { + return nil, err + } + + ackBlockLength, err = utils.GetByteOrder(version).ReadUintN(r, missingSequenceNumberDeltaLen) + if err != nil { + return nil, err + } + + length := protocol.PacketNumber(ackBlockLength) + + if inLongBlock { + frame.AckRanges[len(frame.AckRanges)-1].First -= protocol.PacketNumber(gap) + length + frame.AckRanges[len(frame.AckRanges)-1].Last -= protocol.PacketNumber(gap) + } else { + lastRangeComplete = false + ackRange := AckRange{ + Last: frame.AckRanges[len(frame.AckRanges)-1].First - protocol.PacketNumber(gap) - 1, + } + ackRange.First = ackRange.Last - length + 1 + frame.AckRanges = append(frame.AckRanges, ackRange) + } + + if length > 0 { + lastRangeComplete = true + } + + inLongBlock = (ackBlockLength == 0) + } + + // if the last range was not complete, First and Last make no sense + // remove the range from frame.AckRanges + if !lastRangeComplete { + frame.AckRanges = frame.AckRanges[:len(frame.AckRanges)-1] + } + + frame.LowestAcked = frame.AckRanges[len(frame.AckRanges)-1].First + } else { + if frame.LargestAcked == 0 { + frame.LowestAcked = 0 + } else { + frame.LowestAcked = protocol.PacketNumber(largestAcked + 1 - ackBlockLength) + } + } + + if !frame.validateAckRanges() { + return nil, errInvalidAckRanges + } + + var numTimestamp byte + numTimestamp, err = r.ReadByte() + if err != nil { + return nil, err + } + + if numTimestamp > 0 { + // Delta Largest acked + _, err = r.ReadByte() + if err != nil { + return nil, err + } + // First Timestamp + _, err = utils.GetByteOrder(version).ReadUint32(r) + if err != nil { + return nil, err + } + + for i := 0; i < int(numTimestamp)-1; i++ { + // Delta Largest acked + _, err = r.ReadByte() + if err != nil { + return nil, err + } + + // Time Since Previous Timestamp + _, err = utils.GetByteOrder(version).ReadUint16(r) + if err != nil { + return nil, err + } + } + } + return frame, nil +} + +func (f *AckFrame) writeLegacy(b *bytes.Buffer, version protocol.VersionNumber) error { + largestAckedLen := protocol.GetPacketNumberLength(f.LargestAcked) + + typeByte := uint8(0x40) + + if largestAckedLen != protocol.PacketNumberLen1 { + typeByte ^= (uint8(largestAckedLen / 2)) << 2 + } + + missingSequenceNumberDeltaLen := f.getMissingSequenceNumberDeltaLen() + if missingSequenceNumberDeltaLen != protocol.PacketNumberLen1 { + typeByte ^= (uint8(missingSequenceNumberDeltaLen / 2)) + } + + if f.HasMissingRanges() { + typeByte |= 0x20 + } + + b.WriteByte(typeByte) + + switch largestAckedLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(f.LargestAcked)) + case protocol.PacketNumberLen2: + utils.GetByteOrder(version).WriteUint16(b, uint16(f.LargestAcked)) + case protocol.PacketNumberLen4: + utils.GetByteOrder(version).WriteUint32(b, uint32(f.LargestAcked)) + case protocol.PacketNumberLen6: + utils.GetByteOrder(version).WriteUint48(b, uint64(f.LargestAcked)&(1<<48-1)) + } + + f.DelayTime = time.Since(f.PacketReceivedTime) + utils.GetByteOrder(version).WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond)) + + var numRanges uint64 + var numRangesWritten uint64 + if f.HasMissingRanges() { + numRanges = f.numWritableNackRanges() + if numRanges > 0xFF { + panic("AckFrame: Too many ACK ranges") + } + b.WriteByte(uint8(numRanges - 1)) + } + + var firstAckBlockLength protocol.PacketNumber + if !f.HasMissingRanges() { + firstAckBlockLength = f.LargestAcked - f.LowestAcked + 1 + } else { + if f.LargestAcked != f.AckRanges[0].Last { + return errInconsistentAckLargestAcked + } + if f.LowestAcked != f.AckRanges[len(f.AckRanges)-1].First { + return errInconsistentAckLowestAcked + } + firstAckBlockLength = f.LargestAcked - f.AckRanges[0].First + 1 + numRangesWritten++ + } + + switch missingSequenceNumberDeltaLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(firstAckBlockLength)) + case protocol.PacketNumberLen2: + utils.GetByteOrder(version).WriteUint16(b, uint16(firstAckBlockLength)) + case protocol.PacketNumberLen4: + utils.GetByteOrder(version).WriteUint32(b, uint32(firstAckBlockLength)) + case protocol.PacketNumberLen6: + utils.GetByteOrder(version).WriteUint48(b, uint64(firstAckBlockLength)&(1<<48-1)) + } + + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + + length := ackRange.Last - ackRange.First + 1 + gap := f.AckRanges[i-1].First - ackRange.Last - 1 + + num := gap/0xFF + 1 + if gap%0xFF == 0 { + num-- + } + + if num == 1 { + b.WriteByte(uint8(gap)) + switch missingSequenceNumberDeltaLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(length)) + case protocol.PacketNumberLen2: + utils.GetByteOrder(version).WriteUint16(b, uint16(length)) + case protocol.PacketNumberLen4: + utils.GetByteOrder(version).WriteUint32(b, uint32(length)) + case protocol.PacketNumberLen6: + utils.GetByteOrder(version).WriteUint48(b, uint64(length)&(1<<48-1)) + } + numRangesWritten++ + } else { + for i := 0; i < int(num); i++ { + var lengthWritten uint64 + var gapWritten uint8 + + if i == int(num)-1 { // last block + lengthWritten = uint64(length) + gapWritten = uint8(1 + ((gap - 1) % 255)) + } else { + lengthWritten = 0 + gapWritten = 0xFF + } + + b.WriteByte(gapWritten) + switch missingSequenceNumberDeltaLen { + case protocol.PacketNumberLen1: + b.WriteByte(uint8(lengthWritten)) + case protocol.PacketNumberLen2: + utils.GetByteOrder(version).WriteUint16(b, uint16(lengthWritten)) + case protocol.PacketNumberLen4: + utils.GetByteOrder(version).WriteUint32(b, uint32(lengthWritten)) + case protocol.PacketNumberLen6: + utils.GetByteOrder(version).WriteUint48(b, lengthWritten&(1<<48-1)) + } + + numRangesWritten++ + } + } + + // this is needed if not all AckRanges can be written to the ACK frame (if there are more than 0xFF) + if numRangesWritten >= numRanges { + break + } + } + + if numRanges != numRangesWritten { + return errors.New("BUG: Inconsistent number of ACK ranges written") + } + + b.WriteByte(0) // no timestamps + return nil +} + +func (f *AckFrame) minLengthLegacy(version protocol.VersionNumber) (protocol.ByteCount, error) { + length := protocol.ByteCount(1 + 2 + 1) // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp + length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestAcked)) + + missingSequenceNumberDeltaLen := protocol.ByteCount(f.getMissingSequenceNumberDeltaLen()) + + if f.HasMissingRanges() { + length += (1 + missingSequenceNumberDeltaLen) * protocol.ByteCount(f.numWritableNackRanges()) + } else { + length += missingSequenceNumberDeltaLen + } + // we don't write + return length, nil +} + +// numWritableNackRanges calculates the number of ACK blocks that are about to be written +// this number is different from len(f.AckRanges) for the case of long gaps (> 255 packets) +func (f *AckFrame) numWritableNackRanges() uint64 { + if len(f.AckRanges) == 0 { + return 0 + } + + var numRanges uint64 + for i, ackRange := range f.AckRanges { + if i == 0 { + continue + } + + lastAckRange := f.AckRanges[i-1] + gap := lastAckRange.First - ackRange.Last - 1 + rangeLength := 1 + uint64(gap)/0xFF + if uint64(gap)%0xFF == 0 { + rangeLength-- + } + + if numRanges+rangeLength < 0xFF { + numRanges += rangeLength + } else { + break + } + } + + return numRanges + 1 +} + +func (f *AckFrame) getMissingSequenceNumberDeltaLen() protocol.PacketNumberLen { + var maxRangeLength protocol.PacketNumber + + if f.HasMissingRanges() { + for _, ackRange := range f.AckRanges { + rangeLength := ackRange.Last - ackRange.First + 1 + if rangeLength > maxRangeLength { + maxRangeLength = rangeLength + } + } + } else { + maxRangeLength = f.LargestAcked - f.LowestAcked + 1 + } + + if maxRangeLength <= 0xFF { + return protocol.PacketNumberLen1 + } + if maxRangeLength <= 0xFFFF { + return protocol.PacketNumberLen2 + } + if maxRangeLength <= 0xFFFFFFFF { + return protocol.PacketNumberLen4 + } + + return protocol.PacketNumberLen6 +} diff --git a/internal/wire/ack_frame_legacy_test.go b/internal/wire/ack_frame_legacy_test.go new file mode 100644 index 00000000..a849d406 --- /dev/null +++ b/internal/wire/ack_frame_legacy_test.go @@ -0,0 +1,1281 @@ +package wire + +import ( + "bytes" + "io" + "time" + + "github.com/lucas-clemente/quic-go/internal/protocol" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("ACK Frame (for gQUIC)", func() { + Context("when parsing", func() { + It("accepts a sample frame", func() { + b := bytes.NewReader([]byte{0x40, + 0x1c, // largest acked + 0x0, 0x0, // delay time + 0x1c, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x1c))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame that acks packet number 0", func() { + b := bytes.NewReader([]byte{0x40, + 0x0, // largest acked + 0x0, 0x0, // delay time + 0x1, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with 1 ACKed packet", func() { + b := bytes.NewReader([]byte{0x40, + 0x10, // largest acked + 0x0, 0x0, // delay time + 0x1, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x10))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0x10))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame that acks multiple packets, starting with 0", func() { + b := bytes.NewReader([]byte{0x40, + 0x10, // largest acked + 0x0, 0x0, // delay time + 0x11, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x10))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with multiple timestamps", func() { + b := bytes.NewReader([]byte{0x40, + 0x10, // largest acked + 0x0, 0x0, // timestamp + 0x10, // block length + 0x4, // num timestamps + 0x1, 0x6b, 0x26, 0x4, 0x0, // 1st timestamp + 0x3, 0, 0, // 2nd timestamp + 0x2, 0, 0, // 3rd timestamp + 0x1, 0, 0, // 4th timestamp + }) + _, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Len()).To(BeZero()) + }) + + It("errors when the ACK range is too large", func() { + // LargestAcked: 0x1c + // Length: 0x1d => LowestAcked would be -1 + b := bytes.NewReader([]byte{0x40, + 0x1c, // largest acked + 0x0, 0x0, // delay time + 0x1e, // block length + 0, + }) + _, err := ParseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError(errInvalidAckRanges)) + }) + + It("errors when the first ACK range is empty", func() { + b := bytes.NewReader([]byte{0x40, + 0x9, // largest acked + 0x0, 0x0, // delay time + 0x0, // block length + 0, + }) + _, err := ParseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError("invalid first ACK range")) + }) + + It("parses the delay time", func() { + b := bytes.NewReader([]byte{0x40, + 0x3, // largest acked + 0x0, 0x8e, // delay time + 0x3, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(3))) + Expect(frame.DelayTime).To(Equal(142 * time.Microsecond)) + }) + + It("errors on EOFs", func() { + data := []byte{0x60 ^ 0x4 ^ 0x1, + 0x9, 0x66, // largest acked + 0x23, 0x1, // delay time + 0x7, // num ACk blocks + 0x0, 0x7, // 1st block + 0xff, 0x0, 0x0, // 2nd block + 0xf5, 0x2, 0x8a, // 3rd block + 0xc8, 0x0, 0xe6, // 4th block + 0xff, 0x0, 0x0, // 5th block + 0xff, 0x0, 0x0, // 6th block + 0xff, 0x0, 0x0, // 7th block + 0x23, 0x0, 0x13, // 8th blocks + 0x2, // num timestamps + 0x1, 0x13, 0xae, 0xb, 0x0, // 1st timestamp + 0x0, 0x80, 0x5, // 2nd timestamp + } + _, err := ParseAckFrame(bytes.NewReader(data), versionBigEndian) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := ParseAckFrame(bytes.NewReader(data[0:i]), versionBigEndian) + Expect(err).To(MatchError(io.EOF)) + } + }) + + Context("largest acked length", func() { + It("parses a frame with a 2 byte packet number", func() { + b := bytes.NewReader([]byte{0x40 | 0x4, + 0x13, 0x37, // largest acked + 0x0, 0x0, // delay time + 0x9, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x1337))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0x1337 - 0x9 + 1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with a 4 byte packet number", func() { + b := bytes.NewReader([]byte{0x40 | 0x8, + 0xde, 0xca, 0xfb, 0xad, // largest acked + 0x0, 0x0, // timesatmp + 0x5, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdecafbad))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0xdecafbad - 5 + 1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with a 6 byte packet number", func() { + b := bytes.NewReader([]byte{0x4 | 0xc, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked + 0x0, 0x0, // delay time + 0x5, // block length + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe - 5 + 1))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + }) + + Context("ACK blocks", func() { + It("parses a frame with two ACK blocks", func() { + b := bytes.NewReader([]byte{0x60, + 0x18, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0x3, // 1st block + 0x2, 0x10, // 2nd block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x18))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 0x18 - 0x3 + 1, Last: 0x18})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: (0x18 - 0x3 + 1) - (0x2 + 1) - (0x10 - 1), Last: (0x18 - 0x3 + 1) - (0x2 + 1)})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(4))) + Expect(b.Len()).To(BeZero()) + }) + + It("rejects a frame with invalid ACK ranges", func() { + // like the test before, but increased the last ACK range, such that the First would be negative + b := bytes.NewReader([]byte{0x60, + 0x18, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0x3, // 1st block + 0x2, 0x15, // 2nd block + 0, + }) + _, err := ParseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError(errInvalidAckRanges)) + }) + + It("rejects a frame that says it has ACK blocks in the typeByte, but doesn't have any", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x3, + 0x4, // largest acked + 0x0, 0x0, // delay time + 0, // num ACK blocks + 0, + }) + _, err := ParseAckFrame(b, versionBigEndian) + Expect(err).To(MatchError(errInvalidAckRanges)) + }) + + It("parses a frame with multiple single packets missing", func() { + b := bytes.NewReader([]byte{0x60, + 0x27, // largest acked + 0x0, 0x0, // delay time + 0x6, // num ACK blocks + 0x9, // 1st block + 0x1, 0x1, // 2nd block + 0x1, 0x1, // 3rd block + 0x1, 0x1, // 4th block + 0x1, 0x1, // 5th block + 0x1, 0x1, // 6th block + 0x1, 0x13, // 7th block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x27))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(7)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 31, Last: 0x27})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 29, Last: 29})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 27, Last: 27})) + Expect(frame.AckRanges[3]).To(Equal(AckRange{First: 25, Last: 25})) + Expect(frame.AckRanges[4]).To(Equal(AckRange{First: 23, Last: 23})) + Expect(frame.AckRanges[5]).To(Equal(AckRange{First: 21, Last: 21})) + Expect(frame.AckRanges[6]).To(Equal(AckRange{First: 1, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with multiple longer ACK blocks", func() { + b := bytes.NewReader([]byte{0x60, + 0x52, // largest acked + 0xd1, 0x0, //delay time + 0x3, // num ACK blocks + 0x17, // 1st block + 0xa, 0x10, // 2nd block + 0x4, 0x8, // 3rd block + 0x2, 0x12, // 4th block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x52))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(4)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 60, Last: 0x52})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 34, Last: 49})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 22, Last: 29})) + Expect(frame.AckRanges[3]).To(Equal(AckRange{First: 2, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(2))) + Expect(b.Len()).To(BeZero()) + }) + + Context("more than 256 lost packets in a row", func() { + // 255 missing packets fit into a single ACK block + It("parses a frame with a range of 255 missing packets", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x1, 0x15, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0x3, // 1st block + 0xff, 0x13, // 2nd block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x115))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 20 + 255, Last: 0x115})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + // 256 missing packets fit into two ACK blocks + It("parses a frame with a range of 256 missing packets", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x1, 0x14, // largest acked + 0x0, 0x0, // delay time + 0x2, // num ACK blocks + 0x1, // 1st block + 0xff, 0x0, // 2nd block + 0x1, 0x13, // 3rd block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x114))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 20 + 256, Last: 0x114})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with an incomplete range at the end", func() { + // this is a modified ACK frame that has 5 instead of originally 6 written ranges + // each gap is 300 packets and thus takes 2 ranges + // the last range is incomplete, and should be completely ignored + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x3, 0x9b, // largest acked + 0x0, 0x0, // delay time + 0x5, // num ACK blocks, instead of 0x6 + 0x1, // 1st block + 0xff, 0x0, // 2nd block + 0x2d, 0x1, // 3rd block + 0xff, 0x0, // 4th block + 0x2d, 0x1, // 5th block + 0xff, 0x0, /*0x2d, 0x14,*/ // 6th block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x39b))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(3)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 20 + 3*301, Last: 20 + 3*301})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 20 + 2*301, Last: 20 + 2*301})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 20 + 1*301, Last: 20 + 1*301})) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with one long range, spanning 2 blocks, of missing packets", func() { + // 280 missing packets + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x1, 0x44, // largest acked + 0x0, 0x0, // delay time + 0x2, // num ACK blocks + 0x19, // 1st block + 0xff, 0x0, // 2nd block + 0x19, 0x13, // 3rd block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x144))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 300, Last: 0x144})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with one long range, spanning multiple blocks, of missing packets", func() { + // 2345 missing packets + b := bytes.NewReader([]byte{0x60 ^ 0x4, + 0x9, 0x5b, // largest acked + 0x0, 0x0, // delay time + 0xa, // num ACK blocks + 0x1f, // 1st block + 0xff, 0x0, // 2nd block + 0xff, 0x0, // 3rd block + 0xff, 0x0, // 4th block + 0xff, 0x0, // 5th block + 0xff, 0x0, // 6th block + 0xff, 0x0, // 7th block + 0xff, 0x0, // 8th block + 0xff, 0x0, // 9th block + 0xff, 0x0, // 10th block + 0x32, 0x13, // 11th block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x95b))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 2365, Last: 0x95b})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with multiple 2 byte long ranges of missing packets", func() { + b := bytes.NewReader([]byte{0x60 ^ 0x4 ^ 0x1, + 0x9, 0x66, // largest acked + 0x0, 0x0, // delay time + 0x7, // num ACK blocks + 0x0, 0x7, // 1st block + 0xff, 0x0, 0x0, // 2nd block + 0xf5, 0x2, 0x8a, // 3rd block + 0xc8, 0x0, 0xe6, // 4th block + 0xff, 0x0, 0x0, // 5th block + 0xff, 0x0, 0x0, // 6th block + 0xff, 0x0, 0x0, // 7th block + 0x23, 0x0, 0x13, // 8th block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x966))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(4)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 2400, Last: 0x966})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1250, Last: 1899})) + Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 820, Last: 1049})) + Expect(frame.AckRanges[3]).To(Equal(AckRange{First: 1, Last: 19})) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(b.Len()).To(BeZero()) + }) + + It("parses a frame with with a 4 byte ack block length", func() { + b := bytes.NewReader([]byte{0x60 ^ 0xc ^ 0x2, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACK blocks + 0, 0, 0x13, 0x37, // 1st block + 0x20, 0x12, 0x34, 0x56, 0x78, // 2nd block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 0xdeadbeefcafe - 0x1337 + 1, Last: 0xdeadbeefcafe})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1) - (0x12345678 - 1), Last: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1)})) + }) + + It("parses a frame with with a 6 byte ack block length", func() { + b := bytes.NewReader([]byte{0x60 ^ 0xc ^ 0x3, + 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked + 0x0, 0x0, // delay time + 0x1, // num ACk blocks + 0, 0, 0, 0, 0x13, 0x37, // 1st block + 0x20, 0x0, 0xab, 0x12, 0x34, 0x56, 0x78, // 2nd block + 0, + }) + frame, err := ParseAckFrame(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 0xdeadbeefcafe - 0x1337 + 1, Last: 0xdeadbeefcafe})) + Expect(frame.AckRanges[1]).To(Equal(AckRange{First: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1) - (0xab12345678 - 1), Last: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1)})) + }) + }) + }) + }) + + Context("when writing", func() { + var b *bytes.Buffer + + BeforeEach(func() { + b = &bytes.Buffer{} + }) + + Context("self-consistency", func() { + It("writes a simple ACK frame", func() { + frameOrig := &AckFrame{ + LargestAcked: 1, + LowestAcked: 1, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK that also acks packet 0", func() { + frameOrig := &AckFrame{ + LargestAcked: 1, + LowestAcked: 0, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes the correct block length in a simple ACK frame", func() { + frameOrig := &AckFrame{ + LargestAcked: 20, + LowestAcked: 10, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a simple ACK frame with a high packet number", func() { + frameOrig := &AckFrame{ + LargestAcked: 0xdeadbeefcafe, + LowestAcked: 0xdeadbeefcafe, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK frame with one packet missing", func() { + frameOrig := &AckFrame{ + LargestAcked: 40, + LowestAcked: 0, + AckRanges: []AckRange{ + {First: 25, Last: 40}, + {First: 0, Last: 23}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes an ACK frame with multiple missing packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 25, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 22, Last: 25}, + {First: 15, Last: 18}, + {First: 13, Last: 13}, + {First: 1, Last: 10}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("rejects a frame with incorrect LargestObserved value", func() { + frame := &AckFrame{ + LargestAcked: 26, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 12, Last: 25}, + {First: 1, Last: 10}, + }, + } + err := frame.Write(b, versionBigEndian) + Expect(err).To(MatchError(errInconsistentAckLargestAcked)) + }) + + It("rejects a frame with incorrect LargestObserved value", func() { + frame := &AckFrame{ + LargestAcked: 25, + LowestAcked: 2, + AckRanges: []AckRange{ + {First: 12, Last: 25}, + {First: 1, Last: 10}, + }, + } + err := frame.Write(b, versionBigEndian) + Expect(err).To(MatchError(errInconsistentAckLowestAcked)) + }) + + Context("longer gaps between ACK blocks", func() { + It("only writes one block for 254 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 300, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 20 + 254, Last: 300}, + {First: 1, Last: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(2))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("only writes one block for 255 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 300, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 20 + 255, Last: 300}, + {First: 1, Last: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(2))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes two blocks for 256 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 300, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 20 + 256, Last: 300}, + {First: 1, Last: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(3))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes two blocks for 510 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 600, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 20 + 510, Last: 600}, + {First: 1, Last: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(3))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes three blocks for 511 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 600, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 20 + 511, Last: 600}, + {First: 1, Last: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(4))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes three blocks for 512 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 600, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 20 + 512, Last: 600}, + {First: 1, Last: 19}, + }, + } + Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(4))) + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes multiple blocks for a lot of lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 3000, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 2900, Last: 3000}, + {First: 1, Last: 19}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + + It("writes multiple longer blocks for 256 lost packets", func() { + frameOrig := &AckFrame{ + LargestAcked: 3600, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 2900, Last: 3600}, + {First: 1000, Last: 2500}, + {First: 1, Last: 19}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + }) + }) + + Context("largest acked length", func() { + It("writes a 1 largest acked", func() { + frameOrig := &AckFrame{ + LargestAcked: 200, + LowestAcked: 1, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x0))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 2 byte largest acked", func() { + frameOrig := &AckFrame{ + LargestAcked: 0x100, + LowestAcked: 1, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 4 byte largest acked", func() { + frameOrig := &AckFrame{ + LargestAcked: 0x10000, + LowestAcked: 1, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 6 byte largest acked", func() { + frameOrig := &AckFrame{ + LargestAcked: 0x100000000, + LowestAcked: 1, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(r.Len()).To(BeZero()) + }) + }) + + Context("ack block length", func() { + It("writes a 1 byte ack block length, if all ACK blocks are short", func() { + frameOrig := &AckFrame{ + LargestAcked: 5001, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 5000, Last: 5001}, + {First: 250, Last: 300}, + {First: 1, Last: 200}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x0))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 2 byte ack block length, for a frame with one ACK block", func() { + frameOrig := &AckFrame{ + LargestAcked: 10000, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 9990, Last: 10000}, + {First: 1, Last: 9988}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 2 byte ack block length, for a frame with multiple ACK blocks", func() { + frameOrig := &AckFrame{ + LargestAcked: 10000, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 9990, Last: 10000}, + {First: 1, Last: 256}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 4 byte ack block length, for a frame with single ACK blocks", func() { + frameOrig := &AckFrame{ + LargestAcked: 0xdeadbeef, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 9990, Last: 0xdeadbeef}, + {First: 1, Last: 9988}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 4 byte ack block length, for a frame with multiple ACK blocks", func() { + frameOrig := &AckFrame{ + LargestAcked: 0xdeadbeef, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 9990, Last: 0xdeadbeef}, + {First: 1, Last: 256}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 6 byte ack block length, for a frame with a single ACK blocks", func() { + frameOrig := &AckFrame{ + LargestAcked: 0xdeadbeefcafe, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 9990, Last: 0xdeadbeefcafe}, + {First: 1, Last: 9988}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + + It("writes a 6 byte ack block length, for a frame with multiple ACK blocks", func() { + frameOrig := &AckFrame{ + LargestAcked: 0xdeadbeefcafe, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 9990, Last: 0xdeadbeefcafe}, + {First: 1, Last: 256}, + }, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) + Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) + Expect(r.Len()).To(BeZero()) + }) + }) + + Context("too many ACK blocks", func() { + It("skips the lowest ACK ranges, if there are more than 255 AckRanges", func() { + ackRanges := make([]AckRange, 300) + for i := 1; i <= 300; i++ { + ackRanges[300-i] = AckRange{First: protocol.PacketNumber(3 * i), Last: protocol.PacketNumber(3*i + 1)} + } + frameOrig := &AckFrame{ + LargestAcked: ackRanges[0].Last, + LowestAcked: ackRanges[len(ackRanges)-1].First, + AckRanges: ackRanges, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(ackRanges[254].First)) + Expect(frame.AckRanges).To(HaveLen(0xFF)) + Expect(frame.validateAckRanges()).To(BeTrue()) + }) + + It("skips the lowest ACK ranges, if the gaps are large", func() { + ackRanges := make([]AckRange, 100) + // every AckRange will take 4 written ACK ranges + for i := 1; i <= 100; i++ { + ackRanges[100-i] = AckRange{First: protocol.PacketNumber(1000 * i), Last: protocol.PacketNumber(1000*i + 1)} + } + frameOrig := &AckFrame{ + LargestAcked: ackRanges[0].Last, + LowestAcked: ackRanges[len(ackRanges)-1].First, + AckRanges: ackRanges, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.LowestAcked).To(Equal(ackRanges[255/4].First)) + Expect(frame.validateAckRanges()).To(BeTrue()) + }) + + It("works with huge gaps", func() { + ackRanges := []AckRange{ + {First: 2 * 255 * 200, Last: 2*255*200 + 1}, + {First: 1 * 255 * 200, Last: 1*255*200 + 1}, + {First: 1, Last: 2}, + } + frameOrig := &AckFrame{ + LargestAcked: ackRanges[0].Last, + LowestAcked: ackRanges[len(ackRanges)-1].First, + AckRanges: ackRanges, + } + err := frameOrig.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + r := bytes.NewReader(b.Bytes()) + frame, err := ParseAckFrame(r, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) + Expect(frame.AckRanges).To(HaveLen(2)) + Expect(frame.LowestAcked).To(Equal(ackRanges[1].First)) + Expect(frame.validateAckRanges()).To(BeTrue()) + }) + }) + }) + + Context("min length", func() { + It("has proper min length", func() { + f := &AckFrame{ + LargestAcked: 1, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has proper min length with a large LargestObserved", func() { + f := &AckFrame{ + LargestAcked: 0xDEADBEEFCAFE, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has the proper min length for an ACK with missing packets", func() { + f := &AckFrame{ + LargestAcked: 2000, + LowestAcked: 10, + AckRanges: []AckRange{ + {First: 1000, Last: 2000}, + {First: 50, Last: 900}, + {First: 10, Last: 23}, + }, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has the proper min length for an ACK with long gaps of missing packets", func() { + f := &AckFrame{ + LargestAcked: 2000, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 1500, Last: 2000}, + {First: 290, Last: 295}, + {First: 1, Last: 19}, + }, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + + It("has the proper min length for an ACK with a long ACK range", func() { + largestAcked := protocol.PacketNumber(2 + 0xFFFFFF) + f := &AckFrame{ + LargestAcked: largestAcked, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 1500, Last: largestAcked}, + {First: 290, Last: 295}, + {First: 1, Last: 19}, + }, + } + err := f.Write(b, versionBigEndian) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionBigEndian)).To(Equal(protocol.ByteCount(b.Len()))) + }) + }) + }) + + Context("ACK range validator", func() { + It("accepts an ACK without NACK Ranges", func() { + ack := AckFrame{LargestAcked: 7} + Expect(ack.validateAckRanges()).To(BeTrue()) + }) + + It("rejects ACK ranges with a single range", func() { + ack := AckFrame{ + LargestAcked: 10, + AckRanges: []AckRange{{First: 1, Last: 10}}, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges with Last of the first range unequal to LargestObserved", func() { + ack := AckFrame{ + LargestAcked: 10, + AckRanges: []AckRange{ + {First: 8, Last: 9}, + {First: 2, Last: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges with First greater than Last", func() { + ack := AckFrame{ + LargestAcked: 10, + AckRanges: []AckRange{ + {First: 8, Last: 10}, + {First: 4, Last: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges with First greater than LargestObserved", func() { + ack := AckFrame{ + LargestAcked: 5, + AckRanges: []AckRange{ + {First: 4, Last: 10}, + {First: 1, Last: 2}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges in the wrong order", func() { + ack := AckFrame{ + LargestAcked: 7, + AckRanges: []AckRange{ + {First: 2, Last: 2}, + {First: 6, Last: 7}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects with overlapping ACK ranges", func() { + ack := AckFrame{ + LargestAcked: 7, + AckRanges: []AckRange{ + {First: 5, Last: 7}, + {First: 2, Last: 5}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects ACK ranges that are part of a larger ACK range", func() { + ack := AckFrame{ + LargestAcked: 7, + AckRanges: []AckRange{ + {First: 4, Last: 7}, + {First: 5, Last: 6}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("rejects with directly adjacent ACK ranges", func() { + ack := AckFrame{ + LargestAcked: 7, + AckRanges: []AckRange{ + {First: 5, Last: 7}, + {First: 2, Last: 4}, + }, + } + Expect(ack.validateAckRanges()).To(BeFalse()) + }) + + It("accepts an ACK with one lost packet", func() { + ack := AckFrame{ + LargestAcked: 10, + AckRanges: []AckRange{ + {First: 5, Last: 10}, + {First: 1, Last: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeTrue()) + }) + + It("accepts an ACK with multiple lost packets", func() { + ack := AckFrame{ + LargestAcked: 20, + AckRanges: []AckRange{ + {First: 15, Last: 20}, + {First: 10, Last: 12}, + {First: 1, Last: 3}, + }, + } + Expect(ack.validateAckRanges()).To(BeTrue()) + }) + }) + + Context("check if ACK frame acks a certain packet", func() { + It("works with an ACK without any ranges", func() { + f := AckFrame{ + LowestAcked: 5, + LargestAcked: 10, + } + Expect(f.AcksPacket(1)).To(BeFalse()) + Expect(f.AcksPacket(4)).To(BeFalse()) + Expect(f.AcksPacket(5)).To(BeTrue()) + Expect(f.AcksPacket(8)).To(BeTrue()) + Expect(f.AcksPacket(10)).To(BeTrue()) + Expect(f.AcksPacket(11)).To(BeFalse()) + Expect(f.AcksPacket(20)).To(BeFalse()) + }) + + It("works with an ACK with multiple ACK ranges", func() { + f := AckFrame{ + LowestAcked: 5, + LargestAcked: 20, + AckRanges: []AckRange{ + {First: 15, Last: 20}, + {First: 5, Last: 8}, + }, + } + Expect(f.AcksPacket(4)).To(BeFalse()) + Expect(f.AcksPacket(5)).To(BeTrue()) + Expect(f.AcksPacket(7)).To(BeTrue()) + Expect(f.AcksPacket(8)).To(BeTrue()) + Expect(f.AcksPacket(9)).To(BeFalse()) + Expect(f.AcksPacket(14)).To(BeFalse()) + Expect(f.AcksPacket(15)).To(BeTrue()) + Expect(f.AcksPacket(18)).To(BeTrue()) + Expect(f.AcksPacket(20)).To(BeTrue()) + Expect(f.AcksPacket(21)).To(BeFalse()) + }) + }) +}) diff --git a/internal/wire/ack_frame_test.go b/internal/wire/ack_frame_test.go index 2471312e..ef54ca88 100644 --- a/internal/wire/ack_frame_test.go +++ b/internal/wire/ack_frame_test.go @@ -10,1124 +10,206 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("AckFrame", func() { - Context("when parsing", func() { - It("accepts a sample frame", func() { - b := bytes.NewReader([]byte{0x40, - 0x1c, // largest acked - 0x0, 0x0, // delay time - 0x1c, // block length - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) +var _ = Describe("ACK Frame (for IETF QUIC)", func() { + Context("parsing", func() { + It("parses an ACK frame without any ranges", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(100)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(10)...) // first ack block + b := bytes.NewReader(data) + frame, err := ParseAckFrame(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x1c))) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(100))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(90))) Expect(frame.HasMissingRanges()).To(BeFalse()) Expect(b.Len()).To(BeZero()) }) - It("parses a frame that acks packet number 0", func() { - b := bytes.NewReader([]byte{0x40, - 0x0, // largest acked - 0x0, 0x0, // delay time - 0x1, // block length - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) + It("parses an ACK frame that only acks a single packet", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(55)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(0)...) // first ack block + b := bytes.NewReader(data) + frame, err := ParseAckFrame(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0))) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(55))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(55))) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) + }) + + It("accepts an ACK frame that acks all packets from 0 to largest", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(20)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(20)...) // first ack block + b := bytes.NewReader(data) + frame, err := ParseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(20))) Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0))) Expect(frame.HasMissingRanges()).To(BeFalse()) Expect(b.Len()).To(BeZero()) }) - It("parses a frame with 1 ACKed packet", func() { - b := bytes.NewReader([]byte{0x40, - 0x10, // largest acked - 0x0, 0x0, // delay time - 0x1, // block length - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) + It("rejects an ACK frame that has a first ACK block which is larger than LargestAcked", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(20)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(0)...) // num blocks + data = append(data, encodeVarInt(21)...) // first ack block + b := bytes.NewReader(data) + _, err := ParseAckFrame(b, versionIETFFrames) + Expect(err).To(MatchError("invalid first ACK range")) + }) + + It("parses an ACK frame that has a single block", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(1000)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(1)...) // num blocks + data = append(data, encodeVarInt(100)...) // first ack block + data = append(data, encodeVarInt(98)...) // gap + data = append(data, encodeVarInt(50)...) // ack block + b := bytes.NewReader(data) + frame, err := ParseAckFrame(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x10))) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0x10))) - Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(1000))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(750))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(Equal([]AckRange{ + AckRange{Last: 1000, First: 900}, + AckRange{Last: 800, First: 750}, + })) Expect(b.Len()).To(BeZero()) }) - It("parses a frame that acks multiple packets, starting with 0", func() { - b := bytes.NewReader([]byte{0x40, - 0x10, // largest acked - 0x0, 0x0, // delay time - 0x11, // block length - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) + It("parses an ACK frame that has a multiple blocks", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(100)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(2)...) // num blocks + data = append(data, encodeVarInt(0)...) // first ack block + data = append(data, encodeVarInt(0)...) // gap + data = append(data, encodeVarInt(0)...) // ack block + data = append(data, encodeVarInt(1)...) // gap + data = append(data, encodeVarInt(1)...) // ack block + b := bytes.NewReader(data) + frame, err := ParseAckFrame(b, versionIETFFrames) Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x10))) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0))) - Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(100))) + Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(94))) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(frame.AckRanges).To(Equal([]AckRange{ + AckRange{Last: 100, First: 100}, + AckRange{Last: 98, First: 98}, + AckRange{Last: 95, First: 94}, + })) Expect(b.Len()).To(BeZero()) }) - It("parses a frame with multiple timestamps", func() { - b := bytes.NewReader([]byte{0x40, - 0x10, // largest acked - 0x0, 0x0, // timestamp - 0x10, // block length - 0x4, // num timestamps - 0x1, 0x6b, 0x26, 0x4, 0x0, // 1st timestamp - 0x3, 0, 0, // 2nd timestamp - 0x2, 0, 0, // 3rd timestamp - 0x1, 0, 0, // 4th timestamp - }) - _, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Len()).To(BeZero()) - }) - - It("errors when the ACK range is too large", func() { - // LargestAcked: 0x1c - // Length: 0x1d => LowestAcked would be -1 - b := bytes.NewReader([]byte{0x40, - 0x1c, // largest acked - 0x0, 0x0, // delay time - 0x1e, // block length - 0, - }) - _, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).To(MatchError(ErrInvalidAckRanges)) - }) - - It("errors when the first ACK range is empty", func() { - b := bytes.NewReader([]byte{0x40, - 0x9, // largest acked - 0x0, 0x0, // delay time - 0x0, // block length - 0, - }) - _, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).To(MatchError(ErrInvalidFirstAckRange)) - }) - - Context("in big endian", func() { - It("parses the delay time", func() { - b := bytes.NewReader([]byte{0x40, - 0x3, // largest acked - 0x0, 0x8e, // delay time - 0x3, // block length - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(3))) - Expect(frame.DelayTime).To(Equal(142 * time.Microsecond)) - }) - - It("errors on EOFs", func() { - data := []byte{0x60 ^ 0x4 ^ 0x1, - 0x9, 0x66, // largest acked - 0x23, 0x1, // delay time - 0x7, // num ACk blocks - 0x0, 0x7, // 1st block - 0xff, 0x0, 0x0, // 2nd block - 0xf5, 0x2, 0x8a, // 3rd block - 0xc8, 0x0, 0xe6, // 4th block - 0xff, 0x0, 0x0, // 5th block - 0xff, 0x0, 0x0, // 6th block - 0xff, 0x0, 0x0, // 7th block - 0x23, 0x0, 0x13, // 8th blocks - 0x2, // num timestamps - 0x1, 0x13, 0xae, 0xb, 0x0, // 1st timestamp - 0x0, 0x80, 0x5, // 2nd timestamp - } - _, err := ParseAckFrame(bytes.NewReader(data), versionBigEndian) - Expect(err).NotTo(HaveOccurred()) - for i := range data { - _, err := ParseAckFrame(bytes.NewReader(data[0:i]), versionBigEndian) - Expect(err).To(MatchError(io.EOF)) - } - }) - - Context("largest acked length", func() { - It("parses a frame with a 2 byte packet number", func() { - b := bytes.NewReader([]byte{0x40 | 0x4, - 0x13, 0x37, // largest acked - 0x0, 0x0, // delay time - 0x9, // block length - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x1337))) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0x1337 - 0x9 + 1))) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with a 4 byte packet number", func() { - b := bytes.NewReader([]byte{0x40 | 0x8, - 0xde, 0xca, 0xfb, 0xad, // largest acked - 0x0, 0x0, // timesatmp - 0x5, // block length - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdecafbad))) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0xdecafbad - 5 + 1))) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with a 6 byte packet number", func() { - b := bytes.NewReader([]byte{0x4 | 0xc, - 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked - 0x0, 0x0, // delay time - 0x5, // block length - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe - 5 + 1))) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(b.Len()).To(BeZero()) - }) - }) - }) - - Context("ACK blocks", func() { - It("parses a frame with two ACK blocks", func() { - b := bytes.NewReader([]byte{0x60, - 0x18, // largest acked - 0x0, 0x0, // delay time - 0x1, // num ACK blocks - 0x3, // 1st block - 0x2, 0x10, // 2nd block - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x18))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 0x18 - 0x3 + 1, Last: 0x18})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: (0x18 - 0x3 + 1) - (0x2 + 1) - (0x10 - 1), Last: (0x18 - 0x3 + 1) - (0x2 + 1)})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(4))) - Expect(b.Len()).To(BeZero()) - }) - - It("rejects a frame with invalid ACK ranges", func() { - // like the test before, but increased the last ACK range, such that the First would be negative - b := bytes.NewReader([]byte{0x60, - 0x18, // largest acked - 0x0, 0x0, // delay time - 0x1, // num ACK blocks - 0x3, // 1st block - 0x2, 0x15, // 2nd block - 0, - }) - _, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).To(MatchError(ErrInvalidAckRanges)) - }) - - It("rejects a frame that says it has ACK blocks in the typeByte, but doesn't have any", func() { - b := bytes.NewReader([]byte{0x60 ^ 0x3, - 0x4, // largest acked - 0x0, 0x0, // delay time - 0, // num ACK blocks - 0, - }) - _, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).To(MatchError(ErrInvalidAckRanges)) - }) - - It("parses a frame with multiple single packets missing", func() { - b := bytes.NewReader([]byte{0x60, - 0x27, // largest acked - 0x0, 0x0, // delay time - 0x6, // num ACK blocks - 0x9, // 1st block - 0x1, 0x1, // 2nd block - 0x1, 0x1, // 3rd block - 0x1, 0x1, // 4th block - 0x1, 0x1, // 5th block - 0x1, 0x1, // 6th block - 0x1, 0x13, // 7th block - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x27))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(7)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 31, Last: 0x27})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 29, Last: 29})) - Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 27, Last: 27})) - Expect(frame.AckRanges[3]).To(Equal(AckRange{First: 25, Last: 25})) - Expect(frame.AckRanges[4]).To(Equal(AckRange{First: 23, Last: 23})) - Expect(frame.AckRanges[5]).To(Equal(AckRange{First: 21, Last: 21})) - Expect(frame.AckRanges[6]).To(Equal(AckRange{First: 1, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with multiple longer ACK blocks", func() { - b := bytes.NewReader([]byte{0x60, - 0x52, // largest acked - 0xd1, 0x0, //delay time - 0x3, // num ACK blocks - 0x17, // 1st block - 0xa, 0x10, // 2nd block - 0x4, 0x8, // 3rd block - 0x2, 0x12, // 4th block - 0, - }) - frame, err := ParseAckFrame(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x52))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(4)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 60, Last: 0x52})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 34, Last: 49})) - Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 22, Last: 29})) - Expect(frame.AckRanges[3]).To(Equal(AckRange{First: 2, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(2))) - Expect(b.Len()).To(BeZero()) - }) - - Context("more than 256 lost packets in a row", func() { - // 255 missing packets fit into a single ACK block - It("parses a frame with a range of 255 missing packets", func() { - b := bytes.NewReader([]byte{0x60 ^ 0x4, - 0x1, 0x15, // largest acked - 0x0, 0x0, // delay time - 0x1, // num ACK blocks - 0x3, // 1st block - 0xff, 0x13, // 2nd block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x115))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 20 + 255, Last: 0x115})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) - Expect(b.Len()).To(BeZero()) - }) - - // 256 missing packets fit into two ACK blocks - It("parses a frame with a range of 256 missing packets", func() { - b := bytes.NewReader([]byte{0x60 ^ 0x4, - 0x1, 0x14, // largest acked - 0x0, 0x0, // delay time - 0x2, // num ACK blocks - 0x1, // 1st block - 0xff, 0x0, // 2nd block - 0x1, 0x13, // 3rd block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x114))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 20 + 256, Last: 0x114})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with an incomplete range at the end", func() { - // this is a modified ACK frame that has 5 instead of originally 6 written ranges - // each gap is 300 packets and thus takes 2 ranges - // the last range is incomplete, and should be completely ignored - b := bytes.NewReader([]byte{0x60 ^ 0x4, - 0x3, 0x9b, // largest acked - 0x0, 0x0, // delay time - 0x5, // num ACK blocks, instead of 0x6 - 0x1, // 1st block - 0xff, 0x0, // 2nd block - 0x2d, 0x1, // 3rd block - 0xff, 0x0, // 4th block - 0x2d, 0x1, // 5th block - 0xff, 0x0, /*0x2d, 0x14,*/ // 6th block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x39b))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(3)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 20 + 3*301, Last: 20 + 3*301})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 20 + 2*301, Last: 20 + 2*301})) - Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 20 + 1*301, Last: 20 + 1*301})) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with one long range, spanning 2 blocks, of missing packets", func() { - // 280 missing packets - b := bytes.NewReader([]byte{0x60 ^ 0x4, - 0x1, 0x44, // largest acked - 0x0, 0x0, // delay time - 0x2, // num ACK blocks - 0x19, // 1st block - 0xff, 0x0, // 2nd block - 0x19, 0x13, // 3rd block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x144))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 300, Last: 0x144})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with one long range, spanning multiple blocks, of missing packets", func() { - // 2345 missing packets - b := bytes.NewReader([]byte{0x60 ^ 0x4, - 0x9, 0x5b, // largest acked - 0x0, 0x0, // delay time - 0xa, // num ACK blocks - 0x1f, // 1st block - 0xff, 0x0, // 2nd block - 0xff, 0x0, // 3rd block - 0xff, 0x0, // 4th block - 0xff, 0x0, // 5th block - 0xff, 0x0, // 6th block - 0xff, 0x0, // 7th block - 0xff, 0x0, // 8th block - 0xff, 0x0, // 9th block - 0xff, 0x0, // 10th block - 0x32, 0x13, // 11th block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x95b))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 2365, Last: 0x95b})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) - Expect(b.Len()).To(BeZero()) - }) - - Context("in big endian", func() { - It("parses a frame with multiple 2 byte long ranges of missing packets", func() { - b := bytes.NewReader([]byte{0x60 ^ 0x4 ^ 0x1, - 0x9, 0x66, // largest acked - 0x0, 0x0, // delay time - 0x7, // num ACK blocks - 0x0, 0x7, // 1st block - 0xff, 0x0, 0x0, // 2nd block - 0xf5, 0x2, 0x8a, // 3rd block - 0xc8, 0x0, 0xe6, // 4th block - 0xff, 0x0, 0x0, // 5th block - 0xff, 0x0, 0x0, // 6th block - 0xff, 0x0, 0x0, // 7th block - 0x23, 0x0, 0x13, // 8th block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0x966))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(4)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 2400, Last: 0x966})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: 1250, Last: 1899})) - Expect(frame.AckRanges[2]).To(Equal(AckRange{First: 820, Last: 1049})) - Expect(frame.AckRanges[3]).To(Equal(AckRange{First: 1, Last: 19})) - Expect(frame.LowestAcked).To(Equal(protocol.PacketNumber(1))) - Expect(b.Len()).To(BeZero()) - }) - - It("parses a frame with with a 4 byte ack block length", func() { - b := bytes.NewReader([]byte{0x60 ^ 0xc ^ 0x2, - 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked - 0x0, 0x0, // delay time - 0x1, // num ACK blocks - 0, 0, 0x13, 0x37, // 1st block - 0x20, 0x12, 0x34, 0x56, 0x78, // 2nd block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 0xdeadbeefcafe - 0x1337 + 1, Last: 0xdeadbeefcafe})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1) - (0x12345678 - 1), Last: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1)})) - }) - - It("parses a frame with with a 6 byte ack block length", func() { - b := bytes.NewReader([]byte{0x60 ^ 0xc ^ 0x3, - 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // largest acked - 0x0, 0x0, // delay time - 0x1, // num ACk blocks - 0, 0, 0, 0, 0x13, 0x37, // 1st block - 0x20, 0x0, 0xab, 0x12, 0x34, 0x56, 0x78, // 2nd block - 0, - }) - frame, err := ParseAckFrame(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(protocol.PacketNumber(0xdeadbeefcafe))) - Expect(frame.HasMissingRanges()).To(BeTrue()) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.AckRanges[0]).To(Equal(AckRange{First: 0xdeadbeefcafe - 0x1337 + 1, Last: 0xdeadbeefcafe})) - Expect(frame.AckRanges[1]).To(Equal(AckRange{First: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1) - (0xab12345678 - 1), Last: (0xdeadbeefcafe - 0x1337 + 1) - (0x20 + 1)})) - }) - }) - }) + It("errors on EOF", func() { + data := []byte{0xe} + data = append(data, encodeVarInt(1000)...) // largest acked + data = append(data, encodeVarInt(0)...) // delay + data = append(data, encodeVarInt(1)...) // num blocks + data = append(data, encodeVarInt(100)...) // first ack block + data = append(data, encodeVarInt(98)...) // gap + data = append(data, encodeVarInt(50)...) // ack block + _, err := ParseAckFrame(bytes.NewReader(data), versionIETFFrames) + Expect(err).NotTo(HaveOccurred()) + for i := range data { + _, err := ParseAckFrame(bytes.NewReader(data[0:i]), versionIETFFrames) + Expect(err).To(MatchError(io.EOF)) + } }) }) Context("when writing", func() { - var b *bytes.Buffer - - BeforeEach(func() { - b = &bytes.Buffer{} + It("writes a frame that acks a single packet", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + LargestAcked: 0xdeadbeef, + LowestAcked: 0xdeadbeef, + DelayTime: 18 * time.Second, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := ParseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) }) - Context("self-consistency", func() { - It("writes a simple ACK frame", func() { - frameOrig := &AckFrame{ - LargestAcked: 1, - LowestAcked: 1, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(r.Len()).To(BeZero()) - }) - - It("writes an ACK that also acks packet 0", func() { - frameOrig := &AckFrame{ - LargestAcked: 1, - LowestAcked: 0, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(r.Len()).To(BeZero()) - }) - - It("writes the correct block length in a simple ACK frame", func() { - frameOrig := &AckFrame{ - LargestAcked: 20, - LowestAcked: 10, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a simple ACK frame with a high packet number", func() { - frameOrig := &AckFrame{ - LargestAcked: 0xdeadbeefcafe, - LowestAcked: 0xdeadbeefcafe, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.HasMissingRanges()).To(BeFalse()) - Expect(r.Len()).To(BeZero()) - }) - - It("writes an ACK frame with one packet missing", func() { - frameOrig := &AckFrame{ - LargestAcked: 40, - LowestAcked: 0, - AckRanges: []AckRange{ - {First: 25, Last: 40}, - {First: 0, Last: 23}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes an ACK frame with multiple missing packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 25, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 22, Last: 25}, - {First: 15, Last: 18}, - {First: 13, Last: 13}, - {First: 1, Last: 10}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("rejects a frame with incorrect LargestObserved value", func() { - frame := &AckFrame{ - LargestAcked: 26, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 12, Last: 25}, - {First: 1, Last: 10}, - }, - } - err := frame.Write(b, versionBigEndian) - Expect(err).To(MatchError(errInconsistentAckLargestAcked)) - }) - - It("rejects a frame with incorrect LargestObserved value", func() { - frame := &AckFrame{ - LargestAcked: 25, - LowestAcked: 2, - AckRanges: []AckRange{ - {First: 12, Last: 25}, - {First: 1, Last: 10}, - }, - } - err := frame.Write(b, versionBigEndian) - Expect(err).To(MatchError(errInconsistentAckLowestAcked)) - }) - - Context("longer gaps between ACK blocks", func() { - It("only writes one block for 254 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 300, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 20 + 254, Last: 300}, - {First: 1, Last: 19}, - }, - } - Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(2))) - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("only writes one block for 255 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 300, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 20 + 255, Last: 300}, - {First: 1, Last: 19}, - }, - } - Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(2))) - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("writes two blocks for 256 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 300, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 20 + 256, Last: 300}, - {First: 1, Last: 19}, - }, - } - Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(3))) - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("writes two blocks for 510 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 600, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 20 + 510, Last: 600}, - {First: 1, Last: 19}, - }, - } - Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(3))) - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("writes three blocks for 511 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 600, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 20 + 511, Last: 600}, - {First: 1, Last: 19}, - }, - } - Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(4))) - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("writes three blocks for 512 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 600, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 20 + 512, Last: 600}, - {First: 1, Last: 19}, - }, - } - Expect(frameOrig.numWritableNackRanges()).To(Equal(uint64(4))) - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("writes multiple blocks for a lot of lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 3000, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 2900, Last: 3000}, - {First: 1, Last: 19}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - - It("writes multiple longer blocks for 256 lost packets", func() { - frameOrig := &AckFrame{ - LargestAcked: 3600, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 2900, Last: 3600}, - {First: 1000, Last: 2500}, - {First: 1, Last: 19}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - }) - }) - - Context("largest acked length", func() { - It("writes a 1 largest acked", func() { - frameOrig := &AckFrame{ - LargestAcked: 200, - LowestAcked: 1, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x0))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 2 byte largest acked", func() { - frameOrig := &AckFrame{ - LargestAcked: 0x100, - LowestAcked: 1, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 4 byte largest acked", func() { - frameOrig := &AckFrame{ - LargestAcked: 0x10000, - LowestAcked: 1, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 6 byte largest acked", func() { - frameOrig := &AckFrame{ - LargestAcked: 0x100000000, - LowestAcked: 1, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(r.Len()).To(BeZero()) - }) - }) - - Context("ack block length", func() { - It("writes a 1 byte ack block length, if all ACK blocks are short", func() { - frameOrig := &AckFrame{ - LargestAcked: 5001, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 5000, Last: 5001}, - {First: 250, Last: 300}, - {First: 1, Last: 200}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x0))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 2 byte ack block length, for a frame with one ACK block", func() { - frameOrig := &AckFrame{ - LargestAcked: 10000, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 9990, Last: 10000}, - {First: 1, Last: 9988}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 2 byte ack block length, for a frame with multiple ACK blocks", func() { - frameOrig := &AckFrame{ - LargestAcked: 10000, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 9990, Last: 10000}, - {First: 1, Last: 256}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x1))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 4 byte ack block length, for a frame with single ACK blocks", func() { - frameOrig := &AckFrame{ - LargestAcked: 0xdeadbeef, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 9990, Last: 0xdeadbeef}, - {First: 1, Last: 9988}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 4 byte ack block length, for a frame with multiple ACK blocks", func() { - frameOrig := &AckFrame{ - LargestAcked: 0xdeadbeef, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 9990, Last: 0xdeadbeef}, - {First: 1, Last: 256}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x2))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 6 byte ack block length, for a frame with a single ACK blocks", func() { - frameOrig := &AckFrame{ - LargestAcked: 0xdeadbeefcafe, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 9990, Last: 0xdeadbeefcafe}, - {First: 1, Last: 9988}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - - It("writes a 6 byte ack block length, for a frame with multiple ACK blocks", func() { - frameOrig := &AckFrame{ - LargestAcked: 0xdeadbeefcafe, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 9990, Last: 0xdeadbeefcafe}, - {First: 1, Last: 256}, - }, - } - err := frameOrig.Write(b, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(b.Bytes()[0] & 0x3).To(Equal(byte(0x3))) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, versionBigEndian) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(frameOrig.LowestAcked)) - Expect(frame.AckRanges).To(Equal(frameOrig.AckRanges)) - Expect(r.Len()).To(BeZero()) - }) - }) - - Context("too many ACK blocks", func() { - It("skips the lowest ACK ranges, if there are more than 255 AckRanges", func() { - ackRanges := make([]AckRange, 300) - for i := 1; i <= 300; i++ { - ackRanges[300-i] = AckRange{First: protocol.PacketNumber(3 * i), Last: protocol.PacketNumber(3*i + 1)} - } - frameOrig := &AckFrame{ - LargestAcked: ackRanges[0].Last, - LowestAcked: ackRanges[len(ackRanges)-1].First, - AckRanges: ackRanges, - } - err := frameOrig.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(ackRanges[254].First)) - Expect(frame.AckRanges).To(HaveLen(0xFF)) - Expect(frame.validateAckRanges()).To(BeTrue()) - }) - - It("skips the lowest ACK ranges, if the gaps are large", func() { - ackRanges := make([]AckRange, 100) - // every AckRange will take 4 written ACK ranges - for i := 1; i <= 100; i++ { - ackRanges[100-i] = AckRange{First: protocol.PacketNumber(1000 * i), Last: protocol.PacketNumber(1000*i + 1)} - } - frameOrig := &AckFrame{ - LargestAcked: ackRanges[0].Last, - LowestAcked: ackRanges[len(ackRanges)-1].First, - AckRanges: ackRanges, - } - err := frameOrig.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.LowestAcked).To(Equal(ackRanges[255/4].First)) - Expect(frame.validateAckRanges()).To(BeTrue()) - }) - - It("works with huge gaps", func() { - ackRanges := []AckRange{ - {First: 2 * 255 * 200, Last: 2*255*200 + 1}, - {First: 1 * 255 * 200, Last: 1*255*200 + 1}, - {First: 1, Last: 2}, - } - frameOrig := &AckFrame{ - LargestAcked: ackRanges[0].Last, - LowestAcked: ackRanges[len(ackRanges)-1].First, - AckRanges: ackRanges, - } - err := frameOrig.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - r := bytes.NewReader(b.Bytes()) - frame, err := ParseAckFrame(r, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(frame.LargestAcked).To(Equal(frameOrig.LargestAcked)) - Expect(frame.AckRanges).To(HaveLen(2)) - Expect(frame.LowestAcked).To(Equal(ackRanges[1].First)) - Expect(frame.validateAckRanges()).To(BeTrue()) - }) - }) + It("writes a frame that acks many packets", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + LargestAcked: 0xdecafbad, + LowestAcked: 0x1337, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := ParseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeFalse()) + Expect(b.Len()).To(BeZero()) }) - Context("min length", func() { - It("has proper min length", func() { - f := &AckFrame{ - LargestAcked: 1, - } - err := f.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len()))) - }) + It("writes a frame with a a single gap", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + LargestAcked: 1000, + LowestAcked: 100, + AckRanges: []AckRange{ + {First: 400, Last: 1000}, + {First: 100, Last: 200}, + }, + } + Expect(f.validateAckRanges()).To(BeTrue()) + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := ParseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(b.Len()).To(BeZero()) + }) - It("has proper min length with a large LargestObserved", func() { - f := &AckFrame{ - LargestAcked: 0xDEADBEEFCAFE, - } - err := f.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len()))) - }) - - It("has the proper min length for an ACK with missing packets", func() { - f := &AckFrame{ - LargestAcked: 2000, - LowestAcked: 10, - AckRanges: []AckRange{ - {First: 1000, Last: 2000}, - {First: 50, Last: 900}, - {First: 10, Last: 23}, - }, - } - err := f.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len()))) - }) - - It("has the proper min length for an ACK with long gaps of missing packets", func() { - f := &AckFrame{ - LargestAcked: 2000, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 1500, Last: 2000}, - {First: 290, Last: 295}, - {First: 1, Last: 19}, - }, - } - err := f.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len()))) - }) - - It("has the proper min length for an ACK with a long ACK range", func() { - largestAcked := protocol.PacketNumber(2 + 0xFFFFFF) - f := &AckFrame{ - LargestAcked: largestAcked, - LowestAcked: 1, - AckRanges: []AckRange{ - {First: 1500, Last: largestAcked}, - {First: 290, Last: 295}, - {First: 1, Last: 19}, - }, - } - err := f.Write(b, protocol.VersionWhatever) - Expect(err).ToNot(HaveOccurred()) - Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len()))) - }) + It("writes a frame with multiple ranges", func() { + buf := &bytes.Buffer{} + f := &AckFrame{ + LargestAcked: 10, + LowestAcked: 1, + AckRanges: []AckRange{ + {First: 10, Last: 10}, + {First: 8, Last: 8}, + {First: 5, Last: 6}, + {First: 1, Last: 3}, + }, + } + Expect(f.validateAckRanges()).To(BeTrue()) + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(f.MinLength(versionIETFFrames)).To(BeEquivalentTo(buf.Len())) + b := bytes.NewReader(buf.Bytes()) + frame, err := ParseAckFrame(b, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + Expect(frame).To(Equal(f)) + Expect(frame.HasMissingRanges()).To(BeTrue()) + Expect(b.Len()).To(BeZero()) }) }) diff --git a/packet_packer_test.go b/packet_packer_test.go index 28669b26..eb9e9786 100644 --- a/packet_packer_test.go +++ b/packet_packer_test.go @@ -311,7 +311,8 @@ var _ = Describe("Packet packer", func() { It("packs many control frames into 1 packets", func() { f := &wire.AckFrame{LargestAcked: 1} b := &bytes.Buffer{} - f.Write(b, protocol.VersionWhatever) + err := f.Write(b, packer.version) + Expect(err).ToNot(HaveOccurred()) maxFramesPerPacket := int(maxFrameSize) / b.Len() var controlFrames []wire.Frame for i := 0; i < maxFramesPerPacket; i++ { diff --git a/packet_unpacker.go b/packet_unpacker.go index 3e186c14..7291dc23 100644 --- a/packet_unpacker.go +++ b/packet_unpacker.go @@ -83,12 +83,6 @@ func (u *packetUnpacker) parseIETFFrame(r *bytes.Reader, typeByte byte, hdr *wir err = qerr.Error(qerr.InvalidStreamData, err.Error()) } return frame, err - } else if typeByte&0xc0 == 0x40 { // TODO: implement the IETF ACK frame - frame, err = wire.ParseAckFrame(r, u.version) - if err != nil { - err = qerr.Error(qerr.InvalidAckData, err.Error()) - } - return frame, err } // TODO: implement all IETF QUIC frame types switch typeByte { @@ -128,6 +122,11 @@ func (u *packetUnpacker) parseIETFFrame(r *bytes.Reader, typeByte byte, hdr *wir if err != nil { err = qerr.Error(qerr.InvalidBlockedData, err.Error()) } + case 0xe: + frame, err = wire.ParseAckFrame(r, u.version) + if err != nil { + err = qerr.Error(qerr.InvalidAckData, err.Error()) + } default: err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte)) } diff --git a/packet_unpacker_test.go b/packet_unpacker_test.go index b7794a0b..91e0656a 100644 --- a/packet_unpacker_test.go +++ b/packet_unpacker_test.go @@ -364,6 +364,22 @@ var _ = Describe("Packet unpacker", func() { Expect(packet.frames).To(Equal([]wire.Frame{f})) }) + It("unpacks ACK frames", func() { + f := &wire.AckFrame{ + LargestAcked: 0x13, + LowestAcked: 1, + } + err := f.Write(buf, versionIETFFrames) + Expect(err).ToNot(HaveOccurred()) + setData(buf.Bytes()) + packet, err := unpacker.Unpack(hdrBin, hdr, data) + Expect(err).ToNot(HaveOccurred()) + Expect(packet.frames).To(HaveLen(1)) + readFrame := packet.frames[0].(*wire.AckFrame) + Expect(readFrame).ToNot(BeNil()) + Expect(readFrame.LargestAcked).To(Equal(protocol.PacketNumber(0x13))) + }) + It("errors on invalid type", func() { setData([]byte{0xf}) _, err := unpacker.Unpack(hdrBin, hdr, data) @@ -378,6 +394,7 @@ var _ = Describe("Packet unpacker", func() { 0x05: qerr.InvalidWindowUpdateData, 0x09: qerr.InvalidBlockedData, 0x10: qerr.InvalidStreamData, + 0xe: qerr.InvalidAckData, } { setData([]byte{b}) _, err := unpacker.Unpack(hdrBin, hdr, data)