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, _ 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.BigEndian.ReadUintN(r, largestAckedLen) if err != nil { return nil, err } frame.LargestAcked = protocol.PacketNumber(largestAcked) delay, err := utils.BigEndian.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.BigEndian.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.BigEndian.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.BigEndian.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.BigEndian.ReadUint16(r) if err != nil { return nil, err } } } return frame, nil } func (f *AckFrame) writeLegacy(b *bytes.Buffer, _ 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.BigEndian.WriteUint16(b, uint16(f.LargestAcked)) case protocol.PacketNumberLen4: utils.BigEndian.WriteUint32(b, uint32(f.LargestAcked)) case protocol.PacketNumberLen6: utils.BigEndian.WriteUint48(b, uint64(f.LargestAcked)&(1<<48-1)) } f.DelayTime = time.Since(f.PacketReceivedTime) utils.BigEndian.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.BigEndian.WriteUint16(b, uint16(firstAckBlockLength)) case protocol.PacketNumberLen4: utils.BigEndian.WriteUint32(b, uint32(firstAckBlockLength)) case protocol.PacketNumberLen6: utils.BigEndian.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.BigEndian.WriteUint16(b, uint16(length)) case protocol.PacketNumberLen4: utils.BigEndian.WriteUint32(b, uint32(length)) case protocol.PacketNumberLen6: utils.BigEndian.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.BigEndian.WriteUint16(b, uint16(lengthWritten)) case protocol.PacketNumberLen4: utils.BigEndian.WriteUint32(b, uint32(lengthWritten)) case protocol.PacketNumberLen6: utils.BigEndian.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(_ protocol.VersionNumber) protocol.ByteCount { 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 } // 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 }