From 8da53885fcfe26120b87d0ae94eb60ec5dbccb80 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Fri, 15 Apr 2016 12:34:23 +0700 Subject: [PATCH] split STREAM and ACK frames in seperate files --- ack_frame.go | 26 +++++++ ack_frame_test.go | 21 ++++++ frame.go | 102 +------------------------- stream_frame.go | 84 +++++++++++++++++++++ frame_test.go => stream_frame_test.go | 15 +--- 5 files changed, 133 insertions(+), 115 deletions(-) create mode 100644 ack_frame.go create mode 100644 ack_frame_test.go create mode 100644 stream_frame.go rename frame_test.go => stream_frame_test.go (81%) diff --git a/ack_frame.go b/ack_frame.go new file mode 100644 index 00000000..4de78553 --- /dev/null +++ b/ack_frame.go @@ -0,0 +1,26 @@ +package quic + +import ( + "bytes" + + "github.com/lucas-clemente/quic-go/utils" +) + +// An AckFrame in QUIC +type AckFrame struct { + Entropy byte + LargestObserved uint32 // TODO: change to uint64 +} + +// WriteAckFrame 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, f.LargestObserved) + 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 +} diff --git a/ack_frame_test.go b/ack_frame_test.go new file mode 100644 index 00000000..9ae658e8 --- /dev/null +++ b/ack_frame_test.go @@ -0,0 +1,21 @@ +package quic + +import ( + "bytes" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("AckFrame", func() { + Context("when writing", func() { + It("writes simple frames", func() { + b := &bytes.Buffer{} + (&AckFrame{ + Entropy: 2, + LargestObserved: 1, + }).Write(b) + Expect(b.Bytes()).To(Equal([]byte{0x48, 0x02, 0x01, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0})) + }) + }) +}) diff --git a/frame.go b/frame.go index 3ba31e20..db21aa5e 100644 --- a/frame.go +++ b/frame.go @@ -1,108 +1,8 @@ package quic -import ( - "bytes" - "io/ioutil" - - "github.com/lucas-clemente/quic-go/utils" -) +import "bytes" // A Frame in QUIC type Frame interface { Write(b *bytes.Buffer) error } - -// A StreamFrame of QUIC -type StreamFrame struct { - FinBit bool - StreamID uint32 - Offset uint64 - Data []byte -} - -// ParseStreamFrame reads a stream frame. The type byte must not have been read yet. -func ParseStreamFrame(r *bytes.Reader, typeByte byte) (*StreamFrame, error) { - frame := &StreamFrame{} - - frame.FinBit = typeByte&0x40 > 0 - dataLenPresent := typeByte&0x20 > 0 - offsetLen := typeByte & 0x1C >> 2 - if offsetLen != 0 { - offsetLen++ - } - streamIDLen := typeByte&0x03 + 1 - - sid, err := utils.ReadUintN(r, streamIDLen) - if err != nil { - return nil, err - } - frame.StreamID = uint32(sid) - - frame.Offset, err = utils.ReadUintN(r, offsetLen) - if err != nil { - return nil, err - } - - var dataLen uint16 - if dataLenPresent { - dataLen, err = utils.ReadUint16(r) - if err != nil { - return nil, err - } - } - - if dataLen == 0 { - // The rest of the packet is data - frame.Data, err = ioutil.ReadAll(r) - if err != nil { - return nil, err - } - } else { - frame.Data = make([]byte, dataLen) - if _, err := r.Read(frame.Data); err != nil { - return nil, err - } - } - - return frame, nil -} - -// WriteStreamFrame writes a stream frame. -func (f *StreamFrame) Write(b *bytes.Buffer) error { - typeByte := uint8(0x80) - if f.FinBit { - typeByte ^= 0x40 - } - typeByte ^= 0x20 - if f.Offset != 0 { - typeByte ^= 0x1c // TODO: Send shorter offset if possible - } - typeByte ^= 0x03 // TODO: Send shorter stream ID if possible - b.WriteByte(typeByte) - utils.WriteUint32(b, f.StreamID) - if f.Offset != 0 { - utils.WriteUint64(b, f.Offset) - } - utils.WriteUint16(b, uint16(len(f.Data))) - b.Write(f.Data) - return nil -} - -// An AckFrame in QUIC -type AckFrame struct { - Entropy byte - LargestObserved uint32 // TODO: change to uint64 -} - -// WriteAckFrame 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, f.LargestObserved) - 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 -} diff --git a/stream_frame.go b/stream_frame.go new file mode 100644 index 00000000..432a77ba --- /dev/null +++ b/stream_frame.go @@ -0,0 +1,84 @@ +package quic + +import ( + "bytes" + "io/ioutil" + + "github.com/lucas-clemente/quic-go/utils" +) + +// A StreamFrame of QUIC +type StreamFrame struct { + FinBit bool + StreamID uint32 + Offset uint64 + Data []byte +} + +// ParseStreamFrame reads a stream frame. The type byte must not have been read yet. +func ParseStreamFrame(r *bytes.Reader, typeByte byte) (*StreamFrame, error) { + frame := &StreamFrame{} + + frame.FinBit = typeByte&0x40 > 0 + dataLenPresent := typeByte&0x20 > 0 + offsetLen := typeByte & 0x1C >> 2 + if offsetLen != 0 { + offsetLen++ + } + streamIDLen := typeByte&0x03 + 1 + + sid, err := utils.ReadUintN(r, streamIDLen) + if err != nil { + return nil, err + } + frame.StreamID = uint32(sid) + + frame.Offset, err = utils.ReadUintN(r, offsetLen) + if err != nil { + return nil, err + } + + var dataLen uint16 + if dataLenPresent { + dataLen, err = utils.ReadUint16(r) + if err != nil { + return nil, err + } + } + + if dataLen == 0 { + // The rest of the packet is data + frame.Data, err = ioutil.ReadAll(r) + if err != nil { + return nil, err + } + } else { + frame.Data = make([]byte, dataLen) + if _, err := r.Read(frame.Data); err != nil { + return nil, err + } + } + + return frame, nil +} + +// WriteStreamFrame writes a stream frame. +func (f *StreamFrame) Write(b *bytes.Buffer) error { + typeByte := uint8(0x80) + if f.FinBit { + typeByte ^= 0x40 + } + typeByte ^= 0x20 + if f.Offset != 0 { + typeByte ^= 0x1c // TODO: Send shorter offset if possible + } + typeByte ^= 0x03 // TODO: Send shorter stream ID if possible + b.WriteByte(typeByte) + utils.WriteUint32(b, f.StreamID) + if f.Offset != 0 { + utils.WriteUint64(b, f.Offset) + } + utils.WriteUint16(b, uint16(len(f.Data))) + b.Write(f.Data) + return nil +} diff --git a/frame_test.go b/stream_frame_test.go similarity index 81% rename from frame_test.go rename to stream_frame_test.go index 9a50abf2..15c398fd 100644 --- a/frame_test.go +++ b/stream_frame_test.go @@ -7,7 +7,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("Frame", func() { +var _ = Describe("StreamFrame", func() { Context("stream frames", func() { Context("when parsing", func() { It("accepts sample frame", func() { @@ -52,17 +52,4 @@ var _ = Describe("Frame", func() { }) }) }) - - Context("ACK frames", func() { - Context("when writing", func() { - It("writes simple frames", func() { - b := &bytes.Buffer{} - (&AckFrame{ - Entropy: 2, - LargestObserved: 1, - }).Write(b) - Expect(b.Bytes()).To(Equal([]byte{0x48, 0x02, 0x01, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0})) - }) - }) - }) })