mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
implement parsing and writing of the new ACK frame
This commit is contained in:
parent
11f746a183
commit
d7ceebd644
7 changed files with 1957 additions and 1423 deletions
|
@ -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<<ackDelayExponent) * time.Microsecond
|
||||
numBlocks, err := utils.ReadVarInt(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame.DelayTime = time.Duration(delay) * time.Microsecond
|
||||
|
||||
var numAckBlocks uint8
|
||||
if hasMissingRanges {
|
||||
numAckBlocks, err = r.ReadByte()
|
||||
// read the first ACK range
|
||||
ab, err := utils.ReadVarInt(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ackBlock := protocol.PacketNumber(ab)
|
||||
if ackBlock > 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)))
|
||||
}
|
||||
|
|
381
internal/wire/ack_frame_legacy.go
Normal file
381
internal/wire/ack_frame_legacy.go
Normal file
|
@ -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
|
||||
}
|
1281
internal/wire/ack_frame_legacy_test.go
Normal file
1281
internal/wire/ack_frame_legacy_test.go
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -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++ {
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue