diff --git a/entropy_accumulator.go b/entropy_accumulator.go new file mode 100644 index 000000000..cfa2fbdc6 --- /dev/null +++ b/entropy_accumulator.go @@ -0,0 +1,16 @@ +package quic + +// EntropyAccumulator accumulates the entropy according to the QUIC docs +type EntropyAccumulator byte + +// Add the contribution of the entropy flag of a given packet number +func (e *EntropyAccumulator) Add(packetNumber uint64, entropyFlag bool) { + if entropyFlag { + (*e) ^= 0x01 << (packetNumber % 8) + } +} + +// Get the byte of entropy +func (e *EntropyAccumulator) Get() byte { + return byte(*e) +} diff --git a/entropy_accumulator_test.go b/entropy_accumulator_test.go new file mode 100644 index 000000000..5b149a227 --- /dev/null +++ b/entropy_accumulator_test.go @@ -0,0 +1,25 @@ +package quic + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("EntropyAccumulator", func() { + It("initializes as zero", func() { + var e EntropyAccumulator + Expect(e.Get()).To(BeZero()) + }) + + It("adds entropy", func() { + var e EntropyAccumulator + e.Add(9, true) + Expect(e.Get()).To(Equal(byte(0x02))) + }) + + It("doesn't add entropy for zero entropy flags", func() { + var e EntropyAccumulator + e.Add(9, false) + Expect(e.Get()).To(BeZero()) + }) +}) diff --git a/example/main.go b/example/main.go index 7153a3db8..3cc560f84 100644 --- a/example/main.go +++ b/example/main.go @@ -2,7 +2,6 @@ package main import ( "bytes" - "errors" "fmt" "net" "os" @@ -65,9 +64,8 @@ func main() { panic(err) } - if privateFlag&0x02 > 0 || privateFlag&0x04 > 0 { - panic(errors.New("FEC packets are not implemented")) - } + var entropyAcc quic.EntropyAccumulator + entropyAcc.Add(publicHeader.PacketNumber, privateFlag&0x01 > 0) frame, err := quic.ParseStreamFrame(r) if err != nil { @@ -109,6 +107,7 @@ func main() { replyFrame := &bytes.Buffer{} replyFrame.WriteByte(0) // Private header quic.WriteAckFrame(replyFrame, &quic.AckFrame{ + Entropy: entropyAcc.Get(), LargestObserved: 1, }) quic.WriteStreamFrame(replyFrame, &quic.StreamFrame{ diff --git a/frame.go b/frame.go index 4fb95357c..0e137c227 100644 --- a/frame.go +++ b/frame.go @@ -88,6 +88,7 @@ func WriteStreamFrame(b *bytes.Buffer, f *StreamFrame) { // An AckFrame in QUIC type AckFrame struct { + Entropy byte LargestObserved uint32 // TODO: change to uint64 } @@ -95,7 +96,7 @@ type AckFrame struct { func WriteAckFrame(b *bytes.Buffer, f *AckFrame) { typeByte := uint8(0x48) b.WriteByte(typeByte) - b.WriteByte(0x00) // TODO: Entropy accumulation + b.WriteByte(f.Entropy) utils.WriteUint32(b, f.LargestObserved) utils.WriteUint16(b, 1) // TODO: Ack delay time b.WriteByte(0x01) // Just one timestamp diff --git a/frame_test.go b/frame_test.go index 26124f88c..7121c7525 100644 --- a/frame_test.go +++ b/frame_test.go @@ -58,9 +58,10 @@ var _ = Describe("Frame", func() { It("writes simple frames", func() { b := &bytes.Buffer{} WriteAckFrame(b, &AckFrame{ + Entropy: 2, LargestObserved: 1, }) - Expect(b.Bytes()).To(Equal([]byte{0x48, 0, 0x01, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0})) + Expect(b.Bytes()).To(Equal([]byte{0x48, 0x02, 0x01, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0})) }) }) })