mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-05 13:17:36 +03:00
151 lines
3.6 KiB
Go
151 lines
3.6 KiB
Go
package frames
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
|
|
"github.com/lucas-clemente/quic-go/ackhandler"
|
|
"github.com/lucas-clemente/quic-go/protocol"
|
|
"github.com/lucas-clemente/quic-go/utils"
|
|
)
|
|
|
|
// An AckFrame in QUIC
|
|
type AckFrame struct {
|
|
Entropy byte
|
|
LargestObserved protocol.PacketNumber
|
|
DelayTime uint16 // Todo: properly interpret this value as described in the specification
|
|
NackRanges []*ackhandler.NackRange
|
|
}
|
|
|
|
// Write writes an ACK frame.
|
|
func (f *AckFrame) Write(b *bytes.Buffer) error {
|
|
typeByte := uint8(0x48)
|
|
b.WriteByte(typeByte)
|
|
b.WriteByte(f.Entropy)
|
|
utils.WriteUint32(b, uint32(f.LargestObserved)) // TODO: send the correct length
|
|
utils.WriteUint16(b, 1) // TODO: Ack delay time
|
|
b.WriteByte(0x01) // Just one timestamp
|
|
b.WriteByte(0x00) // Largest observed
|
|
utils.WriteUint32(b, 0) // First timestamp
|
|
return nil
|
|
}
|
|
|
|
// HasNACK returns if the frame has NACK ranges
|
|
func (f *AckFrame) HasNACK() bool {
|
|
if len(f.NackRanges) > 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ParseAckFrame reads an ACK frame
|
|
func ParseAckFrame(r *bytes.Reader) (*AckFrame, error) {
|
|
frame := &AckFrame{}
|
|
|
|
typeByte, err := r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hasNACK := false
|
|
if typeByte&0x20 == 0x20 {
|
|
hasNACK = true
|
|
}
|
|
if typeByte&0x10 == 0x10 {
|
|
panic("truncated ACKs not yet implemented.")
|
|
}
|
|
|
|
largestObservedLen := 2 * ((typeByte & 0x0C) >> 2)
|
|
if largestObservedLen == 0 {
|
|
largestObservedLen = 1
|
|
}
|
|
|
|
missingSequenceNumberDeltaLen := 2 * (typeByte & 0x03)
|
|
if missingSequenceNumberDeltaLen == 0 {
|
|
missingSequenceNumberDeltaLen = 1
|
|
}
|
|
_ = missingSequenceNumberDeltaLen
|
|
|
|
frame.Entropy, err = r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
largestObserved, err := utils.ReadUintN(r, largestObservedLen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
frame.LargestObserved = protocol.PacketNumber(largestObserved)
|
|
|
|
frame.DelayTime, err = utils.ReadUint16(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
numTimestampByte, err := r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
numTimestamp := uint8(numTimestampByte)
|
|
|
|
// Delta Largest observed
|
|
_, err = r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// First Timestamp
|
|
_, err = utils.ReadUint32(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := 0; i < int(numTimestamp)-1; i++ {
|
|
// Delta Largest observed
|
|
_, err = r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Time Since Previous Timestamp
|
|
_, err = utils.ReadUint16(r)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
if hasNACK {
|
|
var numRanges uint8
|
|
numRanges, err = r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i := uint8(0); i < numRanges; i++ {
|
|
missingPacketSequenceNumberDeltaByte, err := r.ReadByte()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
missingPacketSequenceNumberDelta := uint64(missingPacketSequenceNumberDeltaByte)
|
|
|
|
rangeLength, err := utils.ReadUintN(r, largestObservedLen)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nackRange := ackhandler.NackRange{
|
|
Length: uint8(rangeLength + 1),
|
|
}
|
|
if i == 0 {
|
|
nackRange.FirstPacketNumber = frame.LargestObserved - protocol.PacketNumber(missingPacketSequenceNumberDelta+rangeLength)
|
|
} else {
|
|
if missingPacketSequenceNumberDelta == 0 {
|
|
return nil, errors.New("ACK frame: Continues NACK ranges not yet implemented.")
|
|
}
|
|
lastNackRange := frame.NackRanges[len(frame.NackRanges)-1]
|
|
nackRange.FirstPacketNumber = lastNackRange.FirstPacketNumber - protocol.PacketNumber(missingPacketSequenceNumberDelta+rangeLength) - 1
|
|
}
|
|
frame.NackRanges = append(frame.NackRanges, &nackRange)
|
|
}
|
|
}
|
|
|
|
return frame, nil
|
|
}
|