forked from quic-go/quic-go
181
frames/ack_frame_new.go
Normal file
181
frames/ack_frame_new.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package frames
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
"github.com/lucas-clemente/quic-go/utils"
|
||||
)
|
||||
|
||||
// An AckFrameNew is a ACK frame in QUIC c34
|
||||
type AckFrameNew struct {
|
||||
// TODO: rename to LargestAcked
|
||||
LargestObserved protocol.PacketNumber
|
||||
NackRanges []NackRange // has to be ordered. The NACK range with the highest FirstPacketNumber goes first, the NACK range with the lowest FirstPacketNumber goes last
|
||||
|
||||
DelayTime time.Duration
|
||||
PacketReceivedTime time.Time // only for received packets. Will not be modified for received ACKs frames
|
||||
}
|
||||
|
||||
// ParseAckFrameNew reads an ACK frame
|
||||
func ParseAckFrameNew(r *bytes.Reader, version protocol.VersionNumber) (*AckFrameNew, error) {
|
||||
frame := &AckFrameNew{}
|
||||
|
||||
typeByte, err := r.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasNACK := false
|
||||
if typeByte&0x20 == 0x20 {
|
||||
hasNACK = true
|
||||
}
|
||||
|
||||
if hasNACK {
|
||||
panic("NACKs not yet implemented")
|
||||
}
|
||||
|
||||
largestObservedLen := 2 * ((typeByte & 0x0C) >> 2)
|
||||
if largestObservedLen == 0 {
|
||||
largestObservedLen = 1
|
||||
}
|
||||
|
||||
missingSequenceNumberDeltaLen := 2 * (typeByte & 0x03)
|
||||
if missingSequenceNumberDeltaLen == 0 {
|
||||
missingSequenceNumberDeltaLen = 1
|
||||
}
|
||||
|
||||
largestObserved, err := utils.ReadUintN(r, largestObservedLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame.LargestObserved = protocol.PacketNumber(largestObserved)
|
||||
|
||||
delay, err := utils.ReadUfloat16(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frame.DelayTime = time.Duration(delay) * time.Microsecond
|
||||
|
||||
// TODO: read number of ACK blocks if n flag is set
|
||||
|
||||
ackBlockLength, err := utils.ReadUintN(r, missingSequenceNumberDeltaLen)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
utils.Debugf("ackBlockLength: %d", ackBlockLength)
|
||||
|
||||
// TODO: read ACK blocks
|
||||
|
||||
var numTimestampByte byte
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
return frame, nil
|
||||
}
|
||||
|
||||
// Write writes an ACK frame.
|
||||
func (f *AckFrameNew) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
|
||||
largestObservedLen := protocol.GetPacketNumberLength(f.LargestObserved)
|
||||
|
||||
typeByte := uint8(0x40)
|
||||
|
||||
if largestObservedLen != protocol.PacketNumberLen1 {
|
||||
typeByte ^= (uint8(largestObservedLen / 2)) << 2
|
||||
}
|
||||
|
||||
missingSequenceNumberDeltaLen := largestObservedLen
|
||||
if missingSequenceNumberDeltaLen != protocol.PacketNumberLen1 {
|
||||
typeByte ^= (uint8(missingSequenceNumberDeltaLen / 2))
|
||||
}
|
||||
|
||||
f.DelayTime = time.Now().Sub(f.PacketReceivedTime)
|
||||
|
||||
b.WriteByte(typeByte)
|
||||
|
||||
switch largestObservedLen {
|
||||
case protocol.PacketNumberLen1:
|
||||
b.WriteByte(uint8(f.LargestObserved))
|
||||
case protocol.PacketNumberLen2:
|
||||
utils.WriteUint16(b, uint16(f.LargestObserved))
|
||||
case protocol.PacketNumberLen4:
|
||||
utils.WriteUint32(b, uint32(f.LargestObserved))
|
||||
case protocol.PacketNumberLen6:
|
||||
utils.WriteUint48(b, uint64(f.LargestObserved))
|
||||
}
|
||||
|
||||
utils.WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond))
|
||||
|
||||
// TODO: write number of ACK blocks, if present
|
||||
|
||||
switch missingSequenceNumberDeltaLen {
|
||||
case protocol.PacketNumberLen1:
|
||||
b.WriteByte(uint8(f.LargestObserved))
|
||||
case protocol.PacketNumberLen2:
|
||||
utils.WriteUint16(b, uint16(f.LargestObserved))
|
||||
case protocol.PacketNumberLen4:
|
||||
utils.WriteUint32(b, uint32(f.LargestObserved))
|
||||
case protocol.PacketNumberLen6:
|
||||
utils.WriteUint48(b, uint64(f.LargestObserved))
|
||||
}
|
||||
|
||||
// TODO: write ACK blocks
|
||||
|
||||
b.WriteByte(0x01) // Just one timestamp
|
||||
b.WriteByte(0x00) // Delta Largest observed
|
||||
utils.WriteUint32(b, 0) // First timestamp
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MinLength of a written frame
|
||||
func (f *AckFrameNew) MinLength(version protocol.VersionNumber) (protocol.ByteCount, error) {
|
||||
var length protocol.ByteCount
|
||||
length = 1 + 2 + 1 + 1 + 4 // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp, 1 Delta Largest Observed, 4 FirstTimestamp
|
||||
length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestObserved))
|
||||
// for the first ACK block length
|
||||
length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestObserved))
|
||||
|
||||
length += (1 + 2) * 0 /* TODO: num_timestamps */
|
||||
if f.HasNACK() {
|
||||
panic("NACKs not yet implemented")
|
||||
}
|
||||
return length, nil
|
||||
}
|
||||
|
||||
// HasNACK returns if the frame has NACK ranges
|
||||
func (f *AckFrameNew) HasNACK() bool {
|
||||
if len(f.NackRanges) > 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
84
frames/ack_frame_new_test.go
Normal file
84
frames/ack_frame_new_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package frames
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/protocol"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("AckFrame", func() {
|
||||
Context("when parsing", func() {
|
||||
It("accepts a sample frame", func() {
|
||||
b := bytes.NewReader([]byte{0x40, 0x1a, 0x8e, 0x0, 0x1a, 0x1, 0x1, 0x6b, 0x26, 0x3, 0x0})
|
||||
frame, err := ParseAckFrameNew(b, protocol.Version34)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestObserved).To(Equal(protocol.PacketNumber(0x1a)))
|
||||
Expect(frame.DelayTime).To(Equal(142 * time.Microsecond))
|
||||
Expect(frame.HasNACK()).To(Equal(false))
|
||||
Expect(b.Len()).To(BeZero())
|
||||
})
|
||||
|
||||
It("parses a frame with a 48 bit packet number", func() {
|
||||
b := bytes.NewReader([]byte{0x4c, 0x37, 0x13, 0xad, 0xfb, 0xca, 0xde, 0x0, 0x0, 0x0, 0x1, 0, 0, 0, 0, 0})
|
||||
frame, err := ParseAckFrameNew(b, protocol.Version32)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestObserved).To(Equal(protocol.PacketNumber(0xdecafbad1337)))
|
||||
Expect(b.Len()).To(BeZero())
|
||||
})
|
||||
|
||||
It("parses a frame with multiple timestamps", func() {
|
||||
b := bytes.NewReader([]byte{0x40, 0x10, 0x0, 0x0, 0x10, 0x4, 0x1, 0x6b, 0x26, 0x4, 0x0, 0x3, 0, 0, 0x2, 0, 0, 0x1, 0, 0})
|
||||
_, err := ParseAckFrameNew(b, protocol.Version34)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(b.Len()).To(BeZero())
|
||||
})
|
||||
})
|
||||
|
||||
Context("when writing", func() {
|
||||
var b *bytes.Buffer
|
||||
BeforeEach(func() {
|
||||
b = &bytes.Buffer{}
|
||||
})
|
||||
|
||||
Context("min length", func() {
|
||||
It("has proper min length", func() {
|
||||
f := &AckFrameNew{
|
||||
LargestObserved: 1,
|
||||
}
|
||||
f.Write(b, 0)
|
||||
Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len())))
|
||||
})
|
||||
|
||||
It("has proper min length with a large LargestObserved", func() {
|
||||
f := &AckFrameNew{
|
||||
LargestObserved: 0xDEADBEEFCAFE,
|
||||
}
|
||||
f.Write(b, 0)
|
||||
Expect(f.MinLength(0)).To(Equal(protocol.ByteCount(b.Len())))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("self-consistency checks", func() {
|
||||
var b *bytes.Buffer
|
||||
BeforeEach(func() {
|
||||
b = &bytes.Buffer{}
|
||||
})
|
||||
|
||||
It("is self-consistent for ACK frames without NACK ranges", func() {
|
||||
frameOrig := &AckFrameNew{
|
||||
LargestObserved: 1,
|
||||
}
|
||||
err := frameOrig.Write(b, protocol.Version34)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
r := bytes.NewReader(b.Bytes())
|
||||
frame, err := ParseAckFrameNew(r, protocol.Version34)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(frame.LargestObserved).To(Equal(frameOrig.LargestObserved))
|
||||
Expect(r.Len()).To(BeZero())
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user