split STREAM and ACK frames in seperate files

This commit is contained in:
Marten Seemann
2016-04-15 12:34:23 +07:00
parent 9e87ee8ed9
commit 8da53885fc
5 changed files with 133 additions and 115 deletions

26
ack_frame.go Normal file
View File

@@ -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
}

21
ack_frame_test.go Normal file
View File

@@ -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}))
})
})
})

102
frame.go
View File

@@ -1,108 +1,8 @@
package quic package quic
import ( import "bytes"
"bytes"
"io/ioutil"
"github.com/lucas-clemente/quic-go/utils"
)
// A Frame in QUIC // A Frame in QUIC
type Frame interface { type Frame interface {
Write(b *bytes.Buffer) error 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
}

84
stream_frame.go Normal file
View File

@@ -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
}

View File

@@ -7,7 +7,7 @@ import (
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
var _ = Describe("Frame", func() { var _ = Describe("StreamFrame", func() {
Context("stream frames", func() { Context("stream frames", func() {
Context("when parsing", func() { Context("when parsing", func() {
It("accepts sample frame", 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}))
})
})
})
}) })