From cfccdaed9bd68f455c309e17404e9bba4b43fbeb Mon Sep 17 00:00:00 2001 From: Lucas Clemente Date: Wed, 6 Apr 2016 23:10:52 +0200 Subject: [PATCH] add public header parser --- public_header.go | 84 +++++++++++++++++++++++++++++++++++++++++++ public_header_test.go | 23 ++++++++++++ quic_suite_test.go | 13 +++++++ 3 files changed, 120 insertions(+) create mode 100644 public_header.go create mode 100644 public_header_test.go create mode 100644 quic_suite_test.go diff --git a/public_header.go b/public_header.go new file mode 100644 index 00000000..02fe67a1 --- /dev/null +++ b/public_header.go @@ -0,0 +1,84 @@ +package quic + +import "io" + +// The PublicHeader of a QUIC packet +type PublicHeader struct { + VersionFlag bool + ResetFlag bool + + ConnectionIDLength uint8 + ConnectionID uint64 + + QuicVersion uint32 + + PacketNumberLength uint8 + PacketNumber uint64 +} + +// ParsePublicHeader parses a QUIC packet's public header +func ParsePublicHeader(b io.ByteReader) (*PublicHeader, error) { + header := &PublicHeader{} + + // First byte + publicFlagByte, err := b.ReadByte() + if err != nil { + return nil, err + } + header.VersionFlag = publicFlagByte&0x01 > 0 + header.ResetFlag = publicFlagByte&0x02 > 0 + switch publicFlagByte & 0x0C { + case 0x0C: + header.ConnectionIDLength = 8 + case 0x08: + header.ConnectionIDLength = 4 + case 0x04: + header.ConnectionIDLength = 1 + } + switch publicFlagByte & 0x30 { + case 0x30: + header.PacketNumberLength = 6 + case 0x20: + header.PacketNumberLength = 4 + case 0x10: + header.PacketNumberLength = 2 + case 0x00: + header.PacketNumberLength = 1 + } + + // Connection ID + header.ConnectionID, err = readUint64(b, header.ConnectionIDLength) + if err != nil { + return nil, err + } + + // Version (optional) + if header.VersionFlag { + var v uint64 + v, err = readUint64(b, 4) + if err != nil { + return nil, err + } + header.QuicVersion = uint32(v) + } + + // Packet number + header.PacketNumber, err = readUint64(b, header.PacketNumberLength) + if err != nil { + return nil, err + } + + return header, nil +} + +func readUint64(b io.ByteReader, length uint8) (uint64, error) { + var res uint64 + for i := uint8(0); i < length; i++ { + bt, err := b.ReadByte() + if err != nil { + return 0, err + } + res = res<<8 + uint64(bt) + } + return res, nil +} diff --git a/public_header_test.go b/public_header_test.go new file mode 100644 index 00000000..18196505 --- /dev/null +++ b/public_header_test.go @@ -0,0 +1,23 @@ +package quic + +import ( + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Public Header", func() { + It("parses intial client header", func() { + b := bytes.NewReader([]byte{0xd, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c, 0x51, 0x30, 0x33, 0x30, 0x1}) + publicHeader, err := ParsePublicHeader(b) + Expect(err).ToNot(HaveOccurred()) + Expect(publicHeader.VersionFlag).To(BeTrue()) + Expect(publicHeader.ResetFlag).To(BeFalse()) + Expect(publicHeader.ConnectionIDLength).To(Equal(uint8(8))) + Expect(publicHeader.ConnectionID).ToNot(BeZero()) + Expect(publicHeader.QuicVersion).To(Equal(uint32(0x51303330))) + Expect(publicHeader.PacketNumberLength).To(Equal(uint8(1))) + Expect(publicHeader.PacketNumber).To(Equal(uint64(1))) + }) +}) diff --git a/quic_suite_test.go b/quic_suite_test.go new file mode 100644 index 00000000..31e8db1c --- /dev/null +++ b/quic_suite_test.go @@ -0,0 +1,13 @@ +package quic + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "testing" +) + +func TestQuicGo(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "QUIC Suite") +}