send shorter StreamIDs

fixes #74
This commit is contained in:
Marten Seemann
2016-05-11 00:42:34 +07:00
parent e345270e84
commit 9a99df48a6
6 changed files with 157 additions and 21 deletions

View File

@@ -10,10 +10,11 @@ import (
// A StreamFrame of QUIC
type StreamFrame struct {
FinBit bool
StreamID protocol.StreamID
Offset protocol.ByteCount
Data []byte
FinBit bool
StreamID protocol.StreamID
streamIDLen protocol.ByteCount
Offset protocol.ByteCount
Data []byte
}
// ParseStreamFrame reads a stream frame. The type byte must not have been read yet.
@@ -31,9 +32,9 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) {
if offsetLen != 0 {
offsetLen++
}
streamIDLen := typeByte&0x03 + 1
frame.streamIDLen = protocol.ByteCount(typeByte&0x03 + 1)
sid, err := utils.ReadUintN(r, streamIDLen)
sid, err := utils.ReadUintN(r, uint8(frame.streamIDLen))
if err != nil {
return nil, err
}
@@ -71,17 +72,43 @@ func ParseStreamFrame(r *bytes.Reader) (*StreamFrame, error) {
// WriteStreamFrame writes a stream frame.
func (f *StreamFrame) Write(b *bytes.Buffer, packetNumber protocol.PacketNumber, packetNumberLen protocol.PacketNumberLen, version protocol.VersionNumber) error {
typeByte := uint8(0x80)
typeByte := uint8(0x80) // sets the leftmost bit to 1
if f.FinBit {
typeByte ^= 0x40
}
typeByte ^= 0x20
typeByte ^= 0x20 // dataLenPresent
if f.Offset != 0 {
typeByte ^= 0x1c // TODO: Send shorter offset if possible
}
typeByte ^= 0x03 // TODO: Send shorter stream ID if possible
if f.streamIDLen == 0 {
f.calculateStreamIDLength()
}
switch f.streamIDLen {
case 1:
typeByte ^= 0x0
case 2:
typeByte ^= 0x01
case 3:
typeByte ^= 0x02
case 4:
typeByte ^= 0x03
}
b.WriteByte(typeByte)
utils.WriteUint32(b, uint32(f.StreamID))
switch f.streamIDLen {
case 1:
b.WriteByte(uint8(f.StreamID))
case 2:
utils.WriteUint16(b, uint16(f.StreamID))
case 3:
utils.WriteUint24(b, uint32(f.StreamID))
case 4:
utils.WriteUint32(b, uint32(f.StreamID))
}
if f.Offset != 0 {
utils.WriteUint64(b, uint64(f.Offset))
}
@@ -90,9 +117,25 @@ func (f *StreamFrame) Write(b *bytes.Buffer, packetNumber protocol.PacketNumber,
return nil
}
func (f *StreamFrame) calculateStreamIDLength() {
if f.StreamID < (1 << 8) {
f.streamIDLen = 1
} else if f.StreamID < (1 << 16) {
f.streamIDLen = 2
} else if f.StreamID < (1 << 24) {
f.streamIDLen = 3
} else {
f.streamIDLen = 4
}
}
// MinLength of a written frame
func (f *StreamFrame) MinLength() protocol.ByteCount {
return 1 + 4 + 8 + 2 + 1
if f.streamIDLen == 0 {
f.calculateStreamIDLength()
}
return 1 + f.streamIDLen + 8 + 2 + 1
}
// MaybeSplitOffFrame removes the first n bytes and returns them as a separate frame. If n >= len(n), nil is returned and nothing is modified.

View File

@@ -38,7 +38,7 @@ var _ = Describe("StreamFrame", func() {
StreamID: 1,
Data: []byte("foobar"),
}).Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(b.Bytes()).To(Equal([]byte{0xa3, 0x1, 0, 0, 0, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'}))
Expect(b.Bytes()).To(Equal([]byte{0xa0, 0x1, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'}))
})
It("writes offsets", func() {
@@ -48,7 +48,7 @@ var _ = Describe("StreamFrame", func() {
Offset: 16,
Data: []byte("foobar"),
}).Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(b.Bytes()).To(Equal([]byte{0xbf, 0x1, 0, 0, 0, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'}))
Expect(b.Bytes()).To(Equal([]byte{0xbc, 0x1, 0x10, 0, 0, 0, 0, 0, 0, 0, 0x06, 0x00, 'f', 'o', 'o', 'b', 'a', 'r'}))
})
It("has proper min length", func() {
@@ -61,6 +61,74 @@ var _ = Describe("StreamFrame", func() {
f.Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(f.MinLength()).To(Equal(protocol.ByteCount(b.Len())))
})
Context("lengths of StreamIDs", func() {
It("writes a 2 byte StreamID", func() {
b := &bytes.Buffer{}
(&StreamFrame{
StreamID: 13,
Data: []byte("foobar"),
}).Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x0)))
Expect(b.Bytes()[1]).To(Equal(uint8(13)))
})
It("writes a 2 byte StreamID", func() {
b := &bytes.Buffer{}
(&StreamFrame{
StreamID: 0xCAFE,
Data: []byte("foobar"),
}).Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x1)))
Expect(b.Bytes()[1:3]).To(Equal([]byte{0xFE, 0xCA}))
})
It("writes a 3 byte StreamID", func() {
b := &bytes.Buffer{}
(&StreamFrame{
StreamID: 0x13BEEF,
Data: []byte("foobar"),
}).Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x2)))
Expect(b.Bytes()[1:4]).To(Equal([]byte{0xEF, 0xBE, 0x13}))
})
It("writes a 4 byte StreamID", func() {
b := &bytes.Buffer{}
(&StreamFrame{
StreamID: 0xDECAFBAD,
Data: []byte("foobar"),
}).Write(b, 1, protocol.PacketNumberLen6, 0)
Expect(b.Bytes()[0] & 0x3).To(Equal(uint8(0x3)))
Expect(b.Bytes()[1:5]).To(Equal([]byte{0xAD, 0xFB, 0xCA, 0xDE}))
})
})
})
Context("shortening of StreamIDs", func() {
It("determines the length of a 1 byte StreamID", func() {
f := &StreamFrame{StreamID: 0xFF}
f.calculateStreamIDLength()
Expect(f.streamIDLen).To(Equal(protocol.ByteCount(1)))
})
It("determines the length of a 2 byte StreamID", func() {
f := &StreamFrame{StreamID: 0xFFFF}
f.calculateStreamIDLength()
Expect(f.streamIDLen).To(Equal(protocol.ByteCount(2)))
})
It("determines the length of a 1 byte StreamID", func() {
f := &StreamFrame{StreamID: 0xFFFFFF}
f.calculateStreamIDLength()
Expect(f.streamIDLen).To(Equal(protocol.ByteCount(3)))
})
It("determines the length of a 1 byte StreamID", func() {
f := &StreamFrame{StreamID: 0xFFFFFFFF}
f.calculateStreamIDLength()
Expect(f.streamIDLen).To(Equal(protocol.ByteCount(4)))
})
})
Context("splitting off earlier stream frames", func() {