implement basic ACK frame parsing and writing for QUIC 34

ref #182
This commit is contained in:
Marten Seemann
2016-06-19 16:02:00 +07:00
parent 75f9df4edb
commit 480ae993df
2 changed files with 265 additions and 0 deletions

181
frames/ack_frame_new.go Normal file
View 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
}

View 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())
})
})
})