fix application bug

This commit is contained in:
Jeff
2019-05-13 11:19:18 +08:00
committed by zryfish
parent 996d6fe4c5
commit 5462f51e65
717 changed files with 87703 additions and 53426 deletions

View File

@@ -10,8 +10,7 @@ import (
"github.com/lucas-clemente/quic-go/internal/utils"
)
// TODO: use the value sent in the transport parameters
const ackDelayExponent = 3
var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges")
// An AckFrame is an ACK frame
type AckFrame struct {
@@ -20,11 +19,7 @@ type AckFrame struct {
}
// parseAckFrame reads an ACK frame
func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) {
if !version.UsesIETFFrameFormat() {
return parseAckFrameLegacy(r, version)
}
func parseAckFrame(r *bytes.Reader, ackDelayExponent uint8, version protocol.VersionNumber) (*AckFrame, error) {
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
@@ -104,11 +99,7 @@ func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame,
// Write writes an ACK frame.
func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
if !version.UsesIETFFrameFormat() {
return f.writeLegacy(b, version)
}
b.WriteByte(0x1a)
b.WriteByte(0x2)
utils.WriteVarInt(b, uint64(f.LargestAcked()))
utils.WriteVarInt(b, encodeAckDelay(f.DelayTime))
@@ -130,10 +121,6 @@ func (f *AckFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error
// Length of a written frame
func (f *AckFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return f.lengthLegacy(version)
}
largestAcked := f.AckRanges[0].Largest
numRanges := f.numEncodableAckRanges()
@@ -235,5 +222,5 @@ func (f *AckFrame) AcksPacket(p protocol.PacketNumber) bool {
}
func encodeAckDelay(delay time.Duration) uint64 {
return uint64(delay.Nanoseconds() / (1000 * (1 << ackDelayExponent)))
return uint64(delay.Nanoseconds() / (1000 * (1 << protocol.AckDelayExponent)))
}

View File

@@ -1,364 +0,0 @@
package wire
import (
"bytes"
"errors"
"time"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
var errInvalidAckRanges = errors.New("AckFrame: ACK frame contains invalid ACK ranges")
func parseAckFrameLegacy(r *bytes.Reader, _ protocol.VersionNumber) (*AckFrame, error) {
frame := &AckFrame{}
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
hasMissingRanges := typeByte&0x20 == 0x20
largestAckedLen := 2 * ((typeByte & 0x0C) >> 2)
if largestAckedLen == 0 {
largestAckedLen = 1
}
missingSequenceNumberDeltaLen := 2 * (typeByte & 0x03)
if missingSequenceNumberDeltaLen == 0 {
missingSequenceNumberDeltaLen = 1
}
la, err := utils.BigEndian.ReadUintN(r, largestAckedLen)
if err != nil {
return nil, err
}
largestAcked := protocol.PacketNumber(la)
delay, err := utils.BigEndian.ReadUfloat16(r)
if err != nil {
return nil, err
}
frame.DelayTime = time.Duration(delay) * time.Microsecond
var numAckBlocks uint8
if hasMissingRanges {
numAckBlocks, err = r.ReadByte()
if err != nil {
return nil, err
}
}
if hasMissingRanges && numAckBlocks == 0 {
return nil, errInvalidAckRanges
}
abl, err := utils.BigEndian.ReadUintN(r, missingSequenceNumberDeltaLen)
if err != nil {
return nil, err
}
ackBlockLength := protocol.PacketNumber(abl)
if largestAcked > 0 && ackBlockLength < 1 {
return nil, errors.New("invalid first ACK range")
}
if ackBlockLength > largestAcked+1 {
return nil, errInvalidAckRanges
}
if hasMissingRanges {
ackRange := AckRange{
Smallest: largestAcked - ackBlockLength + 1,
Largest: largestAcked,
}
frame.AckRanges = append(frame.AckRanges, ackRange)
var inLongBlock bool
var lastRangeComplete bool
for i := uint8(0); i < numAckBlocks; i++ {
var gap uint8
gap, err = r.ReadByte()
if err != nil {
return nil, err
}
abl, err := utils.BigEndian.ReadUintN(r, missingSequenceNumberDeltaLen)
if err != nil {
return nil, err
}
ackBlockLength := protocol.PacketNumber(abl)
if inLongBlock {
frame.AckRanges[len(frame.AckRanges)-1].Smallest -= protocol.PacketNumber(gap) + ackBlockLength
frame.AckRanges[len(frame.AckRanges)-1].Largest -= protocol.PacketNumber(gap)
} else {
lastRangeComplete = false
ackRange := AckRange{
Largest: frame.AckRanges[len(frame.AckRanges)-1].Smallest - protocol.PacketNumber(gap) - 1,
}
ackRange.Smallest = ackRange.Largest - ackBlockLength + 1
frame.AckRanges = append(frame.AckRanges, ackRange)
}
if ackBlockLength > 0 {
lastRangeComplete = true
}
inLongBlock = (ackBlockLength == 0)
}
// if the last range was not complete, First and Last make no sense
// remove the range from frame.AckRanges
if !lastRangeComplete {
frame.AckRanges = frame.AckRanges[:len(frame.AckRanges)-1]
}
} else {
frame.AckRanges = make([]AckRange, 1)
if largestAcked != 0 {
frame.AckRanges[0].Largest = largestAcked
frame.AckRanges[0].Smallest = largestAcked + 1 - ackBlockLength
}
}
if !frame.validateAckRanges() {
return nil, errInvalidAckRanges
}
var numTimestamp byte
numTimestamp, err = r.ReadByte()
if err != nil {
return nil, err
}
if numTimestamp > 0 {
// Delta Largest acked
_, err = r.ReadByte()
if err != nil {
return nil, err
}
// First Timestamp
_, err = utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
for i := 0; i < int(numTimestamp)-1; i++ {
// Delta Largest acked
_, err = r.ReadByte()
if err != nil {
return nil, err
}
// Time Since Previous Timestamp
_, err = utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
}
}
return frame, nil
}
func (f *AckFrame) writeLegacy(b *bytes.Buffer, _ protocol.VersionNumber) error {
largestAcked := f.LargestAcked()
largestAckedLen := protocol.GetPacketNumberLength(largestAcked)
typeByte := uint8(0x40)
if largestAckedLen != protocol.PacketNumberLen1 {
typeByte ^= (uint8(largestAckedLen / 2)) << 2
}
missingSequenceNumberDeltaLen := f.getMissingSequenceNumberDeltaLen()
if missingSequenceNumberDeltaLen != protocol.PacketNumberLen1 {
typeByte ^= (uint8(missingSequenceNumberDeltaLen / 2))
}
if f.HasMissingRanges() {
typeByte |= 0x20
}
b.WriteByte(typeByte)
switch largestAckedLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(largestAcked))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(largestAcked))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(largestAcked))
case protocol.PacketNumberLen6:
utils.BigEndian.WriteUint48(b, uint64(largestAcked)&(1<<48-1))
}
utils.BigEndian.WriteUfloat16(b, uint64(f.DelayTime/time.Microsecond))
var numRanges uint64
var numRangesWritten uint64
if f.HasMissingRanges() {
numRanges = f.numWritableNackRanges()
if numRanges > 0xFF {
panic("AckFrame: Too many ACK ranges")
}
b.WriteByte(uint8(numRanges - 1))
}
var firstAckBlockLength protocol.PacketNumber
if !f.HasMissingRanges() {
firstAckBlockLength = largestAcked - f.LowestAcked() + 1
} else {
firstAckBlockLength = largestAcked - f.AckRanges[0].Smallest + 1
numRangesWritten++
}
switch missingSequenceNumberDeltaLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(firstAckBlockLength))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(firstAckBlockLength))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(firstAckBlockLength))
case protocol.PacketNumberLen6:
utils.BigEndian.WriteUint48(b, uint64(firstAckBlockLength)&(1<<48-1))
}
for i, ackRange := range f.AckRanges {
if i == 0 {
continue
}
length := ackRange.Largest - ackRange.Smallest + 1
gap := f.AckRanges[i-1].Smallest - ackRange.Largest - 1
num := gap/0xFF + 1
if gap%0xFF == 0 {
num--
}
if num == 1 {
b.WriteByte(uint8(gap))
switch missingSequenceNumberDeltaLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(length))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(length))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(length))
case protocol.PacketNumberLen6:
utils.BigEndian.WriteUint48(b, uint64(length)&(1<<48-1))
}
numRangesWritten++
} else {
for i := 0; i < int(num); i++ {
var lengthWritten uint64
var gapWritten uint8
if i == int(num)-1 { // last block
lengthWritten = uint64(length)
gapWritten = uint8(1 + ((gap - 1) % 255))
} else {
lengthWritten = 0
gapWritten = 0xFF
}
b.WriteByte(gapWritten)
switch missingSequenceNumberDeltaLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(lengthWritten))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(lengthWritten))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(lengthWritten))
case protocol.PacketNumberLen6:
utils.BigEndian.WriteUint48(b, lengthWritten&(1<<48-1))
}
numRangesWritten++
}
}
// this is needed if not all AckRanges can be written to the ACK frame (if there are more than 0xFF)
if numRangesWritten >= numRanges {
break
}
}
if numRanges != numRangesWritten {
return errors.New("BUG: Inconsistent number of ACK ranges written")
}
b.WriteByte(0) // no timestamps
return nil
}
func (f *AckFrame) lengthLegacy(_ protocol.VersionNumber) protocol.ByteCount {
length := protocol.ByteCount(1 + 2 + 1) // 1 TypeByte, 2 ACK delay time, 1 Num Timestamp
length += protocol.ByteCount(protocol.GetPacketNumberLength(f.LargestAcked()))
missingSequenceNumberDeltaLen := protocol.ByteCount(f.getMissingSequenceNumberDeltaLen())
if f.HasMissingRanges() {
length += (1 + missingSequenceNumberDeltaLen) * protocol.ByteCount(f.numWritableNackRanges())
} else {
length += missingSequenceNumberDeltaLen
}
// we don't write
return length
}
// numWritableNackRanges calculates the number of ACK blocks that are about to be written
// this number is different from len(f.AckRanges) for the case of long gaps (> 255 packets)
func (f *AckFrame) numWritableNackRanges() uint64 {
if len(f.AckRanges) == 0 {
return 0
}
var numRanges uint64
for i, ackRange := range f.AckRanges {
if i == 0 {
continue
}
lastAckRange := f.AckRanges[i-1]
gap := lastAckRange.Smallest - ackRange.Largest - 1
rangeLength := 1 + uint64(gap)/0xFF
if uint64(gap)%0xFF == 0 {
rangeLength--
}
if numRanges+rangeLength < 0xFF {
numRanges += rangeLength
} else {
break
}
}
return numRanges + 1
}
func (f *AckFrame) getMissingSequenceNumberDeltaLen() protocol.PacketNumberLen {
var maxRangeLength protocol.PacketNumber
if f.HasMissingRanges() {
for _, ackRange := range f.AckRanges {
rangeLength := ackRange.Largest - ackRange.Smallest + 1
if rangeLength > maxRangeLength {
maxRangeLength = rangeLength
}
}
} else {
maxRangeLength = f.LargestAcked() - f.LowestAcked() + 1
}
if maxRangeLength <= 0xFF {
return protocol.PacketNumberLen1
}
if maxRangeLength <= 0xFFFF {
return protocol.PacketNumberLen2
}
if maxRangeLength <= 0xFFFFFFFF {
return protocol.PacketNumberLen4
}
return protocol.PacketNumberLen6
}

View File

@@ -1,45 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A BlockedFrame is a BLOCKED frame
type BlockedFrame struct {
Offset protocol.ByteCount
}
// parseBlockedFrame parses a BLOCKED frame
func parseBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*BlockedFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
offset, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &BlockedFrame{
Offset: protocol.ByteCount(offset),
}, nil
}
func (f *BlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
if !version.UsesIETFFrameFormat() {
return (&blockedFrameLegacy{}).Write(b, version)
}
typeByte := uint8(0x08)
b.WriteByte(typeByte)
utils.WriteVarInt(b, uint64(f.Offset))
return nil
}
// Length of a written frame
func (f *BlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return 1 + 4
}
return 1 + utils.VarIntLen(uint64(f.Offset))
}

View File

@@ -1,37 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
type blockedFrameLegacy struct {
StreamID protocol.StreamID
}
// parseBlockedFrameLegacy parses a BLOCKED frame (in gQUIC format)
// The frame returned is
// * a STREAM_BLOCKED frame, if the BLOCKED applies to a stream
// * a BLOCKED frame, if the BLOCKED applies to the connection
func parseBlockedFrameLegacy(r *bytes.Reader, _ protocol.VersionNumber) (Frame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
streamID, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
if streamID == 0 {
return &BlockedFrame{}, nil
}
return &StreamBlockedFrame{StreamID: protocol.StreamID(streamID)}, nil
}
//Write writes a BLOCKED frame
func (f *blockedFrameLegacy) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x05)
utils.BigEndian.WriteUint32(b, uint32(f.StreamID))
return nil
}

View File

@@ -2,52 +2,43 @@ package wire
import (
"bytes"
"errors"
"io"
"math"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/qerr"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// A ConnectionCloseFrame in QUIC
// A ConnectionCloseFrame is a CONNECTION_CLOSE frame
type ConnectionCloseFrame struct {
ErrorCode qerr.ErrorCode
ReasonPhrase string
IsApplicationError bool
ErrorCode qerr.ErrorCode
ReasonPhrase string
}
// parseConnectionCloseFrame reads a CONNECTION_CLOSE frame
func parseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber) (*ConnectionCloseFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
var errorCode qerr.ErrorCode
var reasonPhraseLen uint64
if version.UsesIETFFrameFormat() {
ec, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
errorCode = qerr.ErrorCode(ec)
reasonPhraseLen, err = utils.ReadVarInt(r)
if err != nil {
return nil, err
}
} else {
ec, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
errorCode = qerr.ErrorCode(ec)
length, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
reasonPhraseLen = uint64(length)
f := &ConnectionCloseFrame{IsApplicationError: typeByte == 0x1d}
ec, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
f.ErrorCode = qerr.ErrorCode(ec)
// read the Frame Type, if this is not an application error
if !f.IsApplicationError {
if _, err := utils.ReadVarInt(r); err != nil {
return nil, err
}
}
var reasonPhraseLen uint64
reasonPhraseLen, err = utils.ReadVarInt(r)
if err != nil {
return nil, err
}
// shortcut to prevent the unnecessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet
// reading the whole reason phrase would result in EOF when attempting to READ
@@ -60,37 +51,31 @@ func parseConnectionCloseFrame(r *bytes.Reader, version protocol.VersionNumber)
// this should never happen, since we already checked the reasonPhraseLen earlier
return nil, err
}
return &ConnectionCloseFrame{
ErrorCode: errorCode,
ReasonPhrase: string(reasonPhrase),
}, nil
f.ReasonPhrase = string(reasonPhrase)
return f, nil
}
// Length of a written frame
func (f *ConnectionCloseFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if version.UsesIETFFrameFormat() {
return 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
length := 1 + 2 + utils.VarIntLen(uint64(len(f.ReasonPhrase))) + protocol.ByteCount(len(f.ReasonPhrase))
if !f.IsApplicationError {
length++ // for the frame type
}
return 1 + 4 + 2 + protocol.ByteCount(len(f.ReasonPhrase))
return length
}
// Write writes an CONNECTION_CLOSE frame.
func (f *ConnectionCloseFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
b.WriteByte(0x02)
if len(f.ReasonPhrase) > math.MaxUint16 {
return errors.New("ConnectionFrame: ReasonPhrase too long")
}
if version.UsesIETFFrameFormat() {
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
utils.WriteVarInt(b, uint64(len(f.ReasonPhrase)))
if f.IsApplicationError {
b.WriteByte(0x1d)
} else {
utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode))
utils.BigEndian.WriteUint16(b, uint16(len(f.ReasonPhrase)))
b.WriteByte(0x1c)
}
b.WriteString(f.ReasonPhrase)
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
if !f.IsApplicationError {
utils.WriteVarInt(b, 0)
}
utils.WriteVarInt(b, uint64(len(f.ReasonPhrase)))
b.WriteString(f.ReasonPhrase)
return nil
}

View File

@@ -0,0 +1,71 @@
package wire
import (
"bytes"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A CryptoFrame is a CRYPTO frame
type CryptoFrame struct {
Offset protocol.ByteCount
Data []byte
}
func parseCryptoFrame(r *bytes.Reader, _ protocol.VersionNumber) (*CryptoFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
frame := &CryptoFrame{}
offset, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
frame.Offset = protocol.ByteCount(offset)
dataLen, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
if dataLen > uint64(r.Len()) {
return nil, io.EOF
}
if dataLen != 0 {
frame.Data = make([]byte, dataLen)
if _, err := io.ReadFull(r, frame.Data); err != nil {
// this should never happen, since we already checked the dataLen earlier
return nil, err
}
}
return frame, nil
}
func (f *CryptoFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x6)
utils.WriteVarInt(b, uint64(f.Offset))
utils.WriteVarInt(b, uint64(len(f.Data)))
b.Write(f.Data)
return nil
}
// Length of a written frame
func (f *CryptoFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.Offset)) + utils.VarIntLen(uint64(len(f.Data))) + protocol.ByteCount(len(f.Data))
}
// MaxDataLen returns the maximum data length
func (f *CryptoFrame) MaxDataLen(maxSize protocol.ByteCount) protocol.ByteCount {
// pretend that the data size will be 1 bytes
// if it turns out that varint encoding the length will consume 2 bytes, we need to adjust the data length afterwards
headerLen := 1 + utils.VarIntLen(uint64(f.Offset)) + 1
if headerLen > maxSize {
return 0
}
maxDataLen := maxSize - headerLen
if utils.VarIntLen(uint64(maxDataLen)) != 1 {
maxDataLen--
}
return maxDataLen
}

View File

@@ -0,0 +1,38 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A DataBlockedFrame is a DATA_BLOCKED frame
type DataBlockedFrame struct {
DataLimit protocol.ByteCount
}
func parseDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*DataBlockedFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
offset, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &DataBlockedFrame{
DataLimit: protocol.ByteCount(offset),
}, nil
}
func (f *DataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
typeByte := uint8(0x14)
b.WriteByte(typeByte)
utils.WriteVarInt(b, uint64(f.DataLimit))
return nil
}
// Length of a written frame
func (f *DataBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.DataLimit))
}

View File

@@ -0,0 +1,204 @@
package wire
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// ExtendedHeader is the header of a QUIC packet.
type ExtendedHeader struct {
Header
typeByte byte
PacketNumberLen protocol.PacketNumberLen
PacketNumber protocol.PacketNumber
KeyPhase int
}
func (h *ExtendedHeader) parse(b *bytes.Reader, v protocol.VersionNumber) (*ExtendedHeader, error) {
// read the (now unencrypted) first byte
var err error
h.typeByte, err = b.ReadByte()
if err != nil {
return nil, err
}
if _, err := b.Seek(int64(h.ParsedLen())-1, io.SeekCurrent); err != nil {
return nil, err
}
if h.IsLongHeader {
return h.parseLongHeader(b, v)
}
return h.parseShortHeader(b, v)
}
func (h *ExtendedHeader) parseLongHeader(b *bytes.Reader, v protocol.VersionNumber) (*ExtendedHeader, error) {
if h.typeByte&0xc != 0 {
return nil, errors.New("5th and 6th bit must be 0")
}
if err := h.readPacketNumber(b); err != nil {
return nil, err
}
return h, nil
}
func (h *ExtendedHeader) parseShortHeader(b *bytes.Reader, v protocol.VersionNumber) (*ExtendedHeader, error) {
if h.typeByte&0x18 != 0 {
return nil, errors.New("4th and 5th bit must be 0")
}
h.KeyPhase = int(h.typeByte&0x4) >> 2
if err := h.readPacketNumber(b); err != nil {
return nil, err
}
return h, nil
}
func (h *ExtendedHeader) readPacketNumber(b *bytes.Reader) error {
h.PacketNumberLen = protocol.PacketNumberLen(h.typeByte&0x3) + 1
pn, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen))
if err != nil {
return err
}
h.PacketNumber = protocol.PacketNumber(pn)
return nil
}
// Write writes the Header.
func (h *ExtendedHeader) Write(b *bytes.Buffer, ver protocol.VersionNumber) error {
if h.IsLongHeader {
return h.writeLongHeader(b, ver)
}
return h.writeShortHeader(b, ver)
}
func (h *ExtendedHeader) writeLongHeader(b *bytes.Buffer, v protocol.VersionNumber) error {
var packetType uint8
switch h.Type {
case protocol.PacketTypeInitial:
packetType = 0x0
case protocol.PacketType0RTT:
packetType = 0x1
case protocol.PacketTypeHandshake:
packetType = 0x2
case protocol.PacketTypeRetry:
packetType = 0x3
}
firstByte := 0xc0 | packetType<<4
if h.Type == protocol.PacketTypeRetry {
odcil, err := encodeSingleConnIDLen(h.OrigDestConnectionID)
if err != nil {
return err
}
firstByte |= odcil
} else { // Retry packets don't have a packet number
firstByte |= uint8(h.PacketNumberLen - 1)
}
b.WriteByte(firstByte)
utils.BigEndian.WriteUint32(b, uint32(h.Version))
connIDLen, err := encodeConnIDLen(h.DestConnectionID, h.SrcConnectionID)
if err != nil {
return err
}
b.WriteByte(connIDLen)
b.Write(h.DestConnectionID.Bytes())
b.Write(h.SrcConnectionID.Bytes())
switch h.Type {
case protocol.PacketTypeRetry:
b.Write(h.OrigDestConnectionID.Bytes())
b.Write(h.Token)
return nil
case protocol.PacketTypeInitial:
utils.WriteVarInt(b, uint64(len(h.Token)))
b.Write(h.Token)
}
utils.WriteVarInt(b, uint64(h.Length))
return h.writePacketNumber(b)
}
// TODO: add support for the key phase
func (h *ExtendedHeader) writeShortHeader(b *bytes.Buffer, v protocol.VersionNumber) error {
typeByte := 0x40 | uint8(h.PacketNumberLen-1)
typeByte |= byte(h.KeyPhase << 2)
b.WriteByte(typeByte)
b.Write(h.DestConnectionID.Bytes())
return h.writePacketNumber(b)
}
func (h *ExtendedHeader) writePacketNumber(b *bytes.Buffer) error {
if h.PacketNumberLen == protocol.PacketNumberLenInvalid || h.PacketNumberLen > protocol.PacketNumberLen4 {
return fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen)
}
utils.BigEndian.WriteUintN(b, uint8(h.PacketNumberLen), uint64(h.PacketNumber))
return nil
}
// GetLength determines the length of the Header.
func (h *ExtendedHeader) GetLength(v protocol.VersionNumber) protocol.ByteCount {
if h.IsLongHeader {
length := 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol.ByteCount(h.DestConnectionID.Len()+h.SrcConnectionID.Len()) + protocol.ByteCount(h.PacketNumberLen) + utils.VarIntLen(uint64(h.Length))
if h.Type == protocol.PacketTypeInitial {
length += utils.VarIntLen(uint64(len(h.Token))) + protocol.ByteCount(len(h.Token))
}
return length
}
length := protocol.ByteCount(1 /* type byte */ + h.DestConnectionID.Len())
length += protocol.ByteCount(h.PacketNumberLen)
return length
}
// Log logs the Header
func (h *ExtendedHeader) Log(logger utils.Logger) {
if h.IsLongHeader {
var token string
if h.Type == protocol.PacketTypeInitial || h.Type == protocol.PacketTypeRetry {
if len(h.Token) == 0 {
token = "Token: (empty), "
} else {
token = fmt.Sprintf("Token: %#x, ", h.Token)
}
if h.Type == protocol.PacketTypeRetry {
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sOrigDestConnectionID: %s, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.OrigDestConnectionID, h.Version)
return
}
}
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %#x, PacketNumberLen: %d, Length: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.PacketNumber, h.PacketNumberLen, h.Length, h.Version)
} else {
logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, h.KeyPhase)
}
}
func encodeConnIDLen(dest, src protocol.ConnectionID) (byte, error) {
dcil, err := encodeSingleConnIDLen(dest)
if err != nil {
return 0, err
}
scil, err := encodeSingleConnIDLen(src)
if err != nil {
return 0, err
}
return scil | dcil<<4, nil
}
func encodeSingleConnIDLen(id protocol.ConnectionID) (byte, error) {
len := id.Len()
if len == 0 {
return 0, nil
}
if len < 4 || len > 18 {
return 0, fmt.Errorf("invalid connection ID length: %d bytes", len)
}
return byte(len - 3), nil
}

View File

@@ -2,16 +2,26 @@ package wire
import (
"bytes"
"errors"
"fmt"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/qerr"
"github.com/lucas-clemente/quic-go/internal/qerr"
)
type frameParser struct {
ackDelayExponent uint8
version protocol.VersionNumber
}
// NewFrameParser creates a new frame parser.
func NewFrameParser(v protocol.VersionNumber) FrameParser {
return &frameParser{version: v}
}
// ParseNextFrame parses the next frame
// It skips PADDING frames.
func ParseNextFrame(r *bytes.Reader, hdr *Header, v protocol.VersionNumber) (Frame, error) {
func (p *frameParser) ParseNext(r *bytes.Reader, encLevel protocol.EncryptionLevel) (Frame, error) {
for r.Len() != 0 {
typeByte, _ := r.ReadByte()
if typeByte == 0x0 { // PADDING frame
@@ -19,149 +29,69 @@ func ParseNextFrame(r *bytes.Reader, hdr *Header, v protocol.VersionNumber) (Fra
}
r.UnreadByte()
if !v.UsesIETFFrameFormat() {
return parseGQUICFrame(r, typeByte, hdr, v)
}
return parseIETFFrame(r, typeByte, v)
return p.parseFrame(r, typeByte, encLevel)
}
return nil, nil
}
func parseIETFFrame(r *bytes.Reader, typeByte byte, v protocol.VersionNumber) (Frame, error) {
func (p *frameParser) parseFrame(r *bytes.Reader, typeByte byte, encLevel protocol.EncryptionLevel) (Frame, error) {
var frame Frame
var err error
if typeByte&0xf8 == 0x10 {
frame, err = parseStreamFrame(r, v)
if typeByte&0xf8 == 0x8 {
frame, err = parseStreamFrame(r, p.version)
if err != nil {
err = qerr.Error(qerr.InvalidStreamData, err.Error())
return nil, qerr.Error(qerr.FrameEncodingError, err.Error())
}
return frame, err
return frame, nil
}
// TODO: implement all IETF QUIC frame types
switch typeByte {
case 0x1:
frame, err = parseRstStreamFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidRstStreamData, err.Error())
}
case 0x2:
frame, err = parseConnectionCloseFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidConnectionCloseData, err.Error())
frame, err = parsePingFrame(r, p.version)
case 0x2, 0x3:
ackDelayExponent := p.ackDelayExponent
if encLevel != protocol.Encryption1RTT {
ackDelayExponent = protocol.DefaultAckDelayExponent
}
frame, err = parseAckFrame(r, ackDelayExponent, p.version)
case 0x4:
frame, err = parseMaxDataFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error())
}
frame, err = parseResetStreamFrame(r, p.version)
case 0x5:
frame, err = parseMaxStreamDataFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error())
}
frame, err = parseStopSendingFrame(r, p.version)
case 0x6:
frame, err = parseMaxStreamIDFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidFrameData, err.Error())
}
frame, err = parseCryptoFrame(r, p.version)
case 0x7:
frame, err = parsePingFrame(r, v)
case 0x8:
frame, err = parseBlockedFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidBlockedData, err.Error())
}
case 0x9:
frame, err = parseStreamBlockedFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidBlockedData, err.Error())
}
case 0xa:
frame, err = parseStreamIDBlockedFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidFrameData, err.Error())
}
case 0xc:
frame, err = parseStopSendingFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidFrameData, err.Error())
}
case 0xe:
frame, err = parsePathChallengeFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidFrameData, err.Error())
}
case 0xf:
frame, err = parsePathResponseFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidFrameData, err.Error())
}
case 0x1a, 0x1b:
frame, err = parseAckFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidAckData, err.Error())
}
frame, err = parseNewTokenFrame(r, p.version)
case 0x10:
frame, err = parseMaxDataFrame(r, p.version)
case 0x11:
frame, err = parseMaxStreamDataFrame(r, p.version)
case 0x12, 0x13:
frame, err = parseMaxStreamsFrame(r, p.version)
case 0x14:
frame, err = parseDataBlockedFrame(r, p.version)
case 0x15:
frame, err = parseStreamDataBlockedFrame(r, p.version)
case 0x16, 0x17:
frame, err = parseStreamsBlockedFrame(r, p.version)
case 0x18:
frame, err = parseNewConnectionIDFrame(r, p.version)
case 0x19:
frame, err = parseRetireConnectionIDFrame(r, p.version)
case 0x1a:
frame, err = parsePathChallengeFrame(r, p.version)
case 0x1b:
frame, err = parsePathResponseFrame(r, p.version)
case 0x1c, 0x1d:
frame, err = parseConnectionCloseFrame(r, p.version)
default:
err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte))
err = fmt.Errorf("unknown type byte 0x%x", typeByte)
}
return frame, err
if err != nil {
return nil, qerr.Error(qerr.FrameEncodingError, err.Error())
}
return frame, nil
}
func parseGQUICFrame(r *bytes.Reader, typeByte byte, hdr *Header, v protocol.VersionNumber) (Frame, error) {
var frame Frame
var err error
if typeByte&0x80 == 0x80 {
frame, err = parseStreamFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidStreamData, err.Error())
}
return frame, err
} else if typeByte&0xc0 == 0x40 {
frame, err = parseAckFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidAckData, err.Error())
}
return frame, err
}
switch typeByte {
case 0x1:
frame, err = parseRstStreamFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidRstStreamData, err.Error())
}
case 0x2:
frame, err = parseConnectionCloseFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidConnectionCloseData, err.Error())
}
case 0x3:
frame, err = parseGoawayFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidGoawayData, err.Error())
}
case 0x4:
frame, err = parseWindowUpdateFrame(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidWindowUpdateData, err.Error())
}
case 0x5:
frame, err = parseBlockedFrameLegacy(r, v)
if err != nil {
err = qerr.Error(qerr.InvalidBlockedData, err.Error())
}
case 0x6:
if !v.UsesStopWaitingFrames() {
err = errors.New("STOP_WAITING frames not supported by this QUIC version")
break
}
frame, err = parseStopWaitingFrame(r, hdr.PacketNumber, hdr.PacketNumberLen, v)
if err != nil {
err = qerr.Error(qerr.InvalidStopWaitingData, err.Error())
}
case 0x7:
frame, err = parsePingFrame(r, v)
default:
err = qerr.Error(qerr.InvalidFrameData, fmt.Sprintf("unknown type byte 0x%x", typeByte))
}
return frame, err
func (p *frameParser) SetAckDelayExponent(exp uint8) {
p.ackDelayExponent = exp
}

View File

@@ -1,68 +0,0 @@
package wire
import (
"bytes"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// A GoawayFrame is a GOAWAY frame
type GoawayFrame struct {
ErrorCode qerr.ErrorCode
LastGoodStream protocol.StreamID
ReasonPhrase string
}
// parseGoawayFrame parses a GOAWAY frame
func parseGoawayFrame(r *bytes.Reader, _ protocol.VersionNumber) (*GoawayFrame, error) {
frame := &GoawayFrame{}
if _, err := r.ReadByte(); err != nil {
return nil, err
}
errorCode, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
frame.ErrorCode = qerr.ErrorCode(errorCode)
lastGoodStream, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
frame.LastGoodStream = protocol.StreamID(lastGoodStream)
reasonPhraseLen, err := utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
if reasonPhraseLen > uint16(protocol.MaxReceivePacketSize) {
return nil, qerr.Error(qerr.InvalidGoawayData, "reason phrase too long")
}
reasonPhrase := make([]byte, reasonPhraseLen)
if _, err := io.ReadFull(r, reasonPhrase); err != nil {
return nil, err
}
frame.ReasonPhrase = string(reasonPhrase)
return frame, nil
}
func (f *GoawayFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x03)
utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode))
utils.BigEndian.WriteUint32(b, uint32(f.LastGoodStream))
utils.BigEndian.WriteUint16(b, uint16(len(f.ReasonPhrase)))
b.WriteString(f.ReasonPhrase)
return nil
}
// Length of a written frame
func (f *GoawayFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return protocol.ByteCount(1 + 4 + 4 + 2 + len(f.ReasonPhrase))
}

View File

@@ -2,323 +2,241 @@ package wire
import (
"bytes"
"crypto/rand"
"errors"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// Header is the header of a QUIC packet.
// It contains fields that are only needed for the gQUIC Public Header and the IETF draft Header.
// ParseConnectionID parses the destination connection ID of a packet.
// It uses the data slice for the connection ID.
// That means that the connection ID must not be used after the packet buffer is released.
func ParseConnectionID(data []byte, shortHeaderConnIDLen int) (protocol.ConnectionID, error) {
if len(data) == 0 {
return nil, io.EOF
}
isLongHeader := data[0]&0x80 > 0
if !isLongHeader {
if len(data) < shortHeaderConnIDLen+1 {
return nil, io.EOF
}
return protocol.ConnectionID(data[1 : 1+shortHeaderConnIDLen]), nil
}
if len(data) < 6 {
return nil, io.EOF
}
destConnIDLen, _ := decodeConnIDLen(data[5])
if len(data) < 6+destConnIDLen {
return nil, io.EOF
}
return protocol.ConnectionID(data[6 : 6+destConnIDLen]), nil
}
// IsVersionNegotiationPacket says if this is a version negotiation packet
func IsVersionNegotiationPacket(b []byte) bool {
if len(b) < 5 {
return false
}
return b[0]&0x80 > 0 && b[1] == 0 && b[2] == 0 && b[3] == 0 && b[4] == 0
}
var errUnsupportedVersion = errors.New("unsupported version")
// The Header is the version independent part of the header
type Header struct {
IsPublicHeader bool
Version protocol.VersionNumber
SrcConnectionID protocol.ConnectionID
DestConnectionID protocol.ConnectionID
Raw []byte
Version protocol.VersionNumber
DestConnectionID protocol.ConnectionID
SrcConnectionID protocol.ConnectionID
OrigDestConnectionID protocol.ConnectionID // only needed in the Retry packet
PacketNumberLen protocol.PacketNumberLen
PacketNumber protocol.PacketNumber
IsVersionNegotiation bool
SupportedVersions []protocol.VersionNumber // Version Number sent in a Version Negotiation Packet by the server
// only needed for the gQUIC Public Header
VersionFlag bool
ResetFlag bool
DiversificationNonce []byte
// only needed for the IETF Header
Type protocol.PacketType
IsLongHeader bool
KeyPhase int
PayloadLen protocol.ByteCount
Token []byte
Type protocol.PacketType
Length protocol.ByteCount
Token []byte
SupportedVersions []protocol.VersionNumber // sent in a Version Negotiation Packet
OrigDestConnectionID protocol.ConnectionID // sent in the Retry packet
typeByte byte
parsedLen protocol.ByteCount // how many bytes were read while parsing this header
}
var errInvalidPacketNumberLen = errors.New("invalid packet number length")
// Write writes the Header.
func (h *Header) Write(b *bytes.Buffer, pers protocol.Perspective, ver protocol.VersionNumber) error {
if !ver.UsesIETFHeaderFormat() {
h.IsPublicHeader = true // save that this is a Public Header, so we can log it correctly later
return h.writePublicHeader(b, pers, ver)
// ParsePacket parses a packet.
// If the packet has a long header, the packet is cut according to the length field.
// If we understand the version, the packet is header up unto the packet number.
// Otherwise, only the invariant part of the header is parsed.
func ParsePacket(data []byte, shortHeaderConnIDLen int) (*Header, []byte /* packet data */, []byte /* rest */, error) {
hdr, err := parseHeader(bytes.NewReader(data), shortHeaderConnIDLen)
if err != nil {
if err == errUnsupportedVersion {
return hdr, nil, nil, nil
}
return nil, nil, nil, err
}
// write an IETF QUIC header
if h.IsLongHeader {
return h.writeLongHeader(b, ver)
var rest []byte
if hdr.IsLongHeader {
if protocol.ByteCount(len(data)) < hdr.ParsedLen()+hdr.Length {
return nil, nil, nil, fmt.Errorf("packet length (%d bytes) is smaller than the expected length (%d bytes)", len(data)-int(hdr.ParsedLen()), hdr.Length)
}
packetLen := int(hdr.ParsedLen() + hdr.Length)
rest = data[packetLen:]
data = data[:packetLen]
}
return h.writeShortHeader(b, ver)
return hdr, data, rest, nil
}
// TODO: add support for the key phase
func (h *Header) writeLongHeader(b *bytes.Buffer, v protocol.VersionNumber) error {
b.WriteByte(byte(0x80 | h.Type))
utils.BigEndian.WriteUint32(b, uint32(h.Version))
connIDLen, err := encodeConnIDLen(h.DestConnectionID, h.SrcConnectionID)
// ParseHeader parses the header.
// For short header packets: up to the packet number.
// For long header packets:
// * if we understand the version: up to the packet number
// * if not, only the invariant part of the header
func parseHeader(b *bytes.Reader, shortHeaderConnIDLen int) (*Header, error) {
startLen := b.Len()
h, err := parseHeaderImpl(b, shortHeaderConnIDLen)
if err != nil {
return h, err
}
h.parsedLen = protocol.ByteCount(startLen - b.Len())
return h, err
}
func parseHeaderImpl(b *bytes.Reader, shortHeaderConnIDLen int) (*Header, error) {
typeByte, err := b.ReadByte()
if err != nil {
return nil, err
}
h := &Header{
typeByte: typeByte,
IsLongHeader: typeByte&0x80 > 0,
}
if !h.IsLongHeader {
if h.typeByte&0x40 == 0 {
return nil, errors.New("not a QUIC packet")
}
if err := h.parseShortHeader(b, shortHeaderConnIDLen); err != nil {
return nil, err
}
return h, nil
}
return h, h.parseLongHeader(b)
}
func (h *Header) parseShortHeader(b *bytes.Reader, shortHeaderConnIDLen int) error {
var err error
h.DestConnectionID, err = protocol.ReadConnectionID(b, shortHeaderConnIDLen)
return err
}
func (h *Header) parseLongHeader(b *bytes.Reader) error {
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return err
}
b.WriteByte(connIDLen)
b.Write(h.DestConnectionID.Bytes())
b.Write(h.SrcConnectionID.Bytes())
h.Version = protocol.VersionNumber(v)
if h.Version != 0 && h.typeByte&0x40 == 0 {
return errors.New("not a QUIC packet")
}
connIDLenByte, err := b.ReadByte()
if err != nil {
return err
}
dcil, scil := decodeConnIDLen(connIDLenByte)
h.DestConnectionID, err = protocol.ReadConnectionID(b, dcil)
if err != nil {
return err
}
h.SrcConnectionID, err = protocol.ReadConnectionID(b, scil)
if err != nil {
return err
}
if h.Version == 0 {
return h.parseVersionNegotiationPacket(b)
}
// If we don't understand the version, we have no idea how to interpret the rest of the bytes
if !protocol.IsSupportedVersion(protocol.SupportedVersions, h.Version) {
return errUnsupportedVersion
}
if h.Type == protocol.PacketTypeInitial && v.UsesTokenInHeader() {
utils.WriteVarInt(b, uint64(len(h.Token)))
b.Write(h.Token)
switch (h.typeByte & 0x30) >> 4 {
case 0x0:
h.Type = protocol.PacketTypeInitial
case 0x1:
h.Type = protocol.PacketType0RTT
case 0x2:
h.Type = protocol.PacketTypeHandshake
case 0x3:
h.Type = protocol.PacketTypeRetry
}
if h.Type == protocol.PacketTypeRetry {
odcil, err := encodeSingleConnIDLen(h.OrigDestConnectionID)
odcil := decodeSingleConnIDLen(h.typeByte & 0xf)
h.OrigDestConnectionID, err = protocol.ReadConnectionID(b, odcil)
if err != nil {
return err
}
// randomize the first 4 bits
odcilByte := make([]byte, 1)
_, _ = rand.Read(odcilByte) // it's safe to ignore the error here
odcilByte[0] = (odcilByte[0] & 0xf0) | odcil
b.Write(odcilByte)
b.Write(h.OrigDestConnectionID.Bytes())
b.Write(h.Token)
h.Token = make([]byte, b.Len())
if _, err := io.ReadFull(b, h.Token); err != nil {
return err
}
return nil
}
if v.UsesLengthInHeader() {
utils.WriteVarInt(b, uint64(h.PayloadLen))
}
if v.UsesVarintPacketNumbers() {
return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
}
utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber))
if h.Type == protocol.PacketType0RTT && v == protocol.Version44 {
if len(h.DiversificationNonce) != 32 {
return errors.New("invalid diversification nonce length")
if h.Type == protocol.PacketTypeInitial {
tokenLen, err := utils.ReadVarInt(b)
if err != nil {
return err
}
b.Write(h.DiversificationNonce)
if tokenLen > uint64(b.Len()) {
return io.EOF
}
h.Token = make([]byte, tokenLen)
if _, err := io.ReadFull(b, h.Token); err != nil {
return err
}
}
pl, err := utils.ReadVarInt(b)
if err != nil {
return err
}
h.Length = protocol.ByteCount(pl)
return nil
}
func (h *Header) parseVersionNegotiationPacket(b *bytes.Reader) error {
if b.Len() == 0 {
return errors.New("Version Negoation packet has empty version list")
}
if b.Len()%4 != 0 {
return errors.New("Version Negotation packet has a version list with an invalid length")
}
h.SupportedVersions = make([]protocol.VersionNumber, b.Len()/4)
for i := 0; b.Len() > 0; i++ {
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return err
}
h.SupportedVersions[i] = protocol.VersionNumber(v)
}
return nil
}
func (h *Header) writeShortHeader(b *bytes.Buffer, v protocol.VersionNumber) error {
typeByte := byte(0x30)
typeByte |= byte(h.KeyPhase << 6)
if !v.UsesVarintPacketNumbers() {
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
case protocol.PacketNumberLen2:
typeByte |= 0x1
case protocol.PacketNumberLen4:
typeByte |= 0x2
default:
return errInvalidPacketNumberLen
}
}
b.WriteByte(typeByte)
b.Write(h.DestConnectionID.Bytes())
if !v.UsesVarintPacketNumbers() {
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(h.PacketNumber))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(h.PacketNumber))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber))
}
return nil
}
return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
// ParsedLen returns the number of bytes that were consumed when parsing the header
func (h *Header) ParsedLen() protocol.ByteCount {
return h.parsedLen
}
// writePublicHeader writes a Public Header.
func (h *Header) writePublicHeader(b *bytes.Buffer, pers protocol.Perspective, _ protocol.VersionNumber) error {
if h.ResetFlag || (h.VersionFlag && pers == protocol.PerspectiveServer) {
return errors.New("PublicHeader: Can only write regular packets")
}
if h.SrcConnectionID.Len() != 0 {
return errors.New("PublicHeader: SrcConnectionID must not be set")
}
if len(h.DestConnectionID) != 0 && len(h.DestConnectionID) != 8 {
return fmt.Errorf("PublicHeader: wrong length for Connection ID: %d (expected 8)", len(h.DestConnectionID))
}
publicFlagByte := uint8(0x00)
if h.VersionFlag {
publicFlagByte |= 0x01
}
if h.DestConnectionID.Len() > 0 {
publicFlagByte |= 0x08
}
if len(h.DiversificationNonce) > 0 {
if len(h.DiversificationNonce) != 32 {
return errors.New("invalid diversification nonce length")
}
publicFlagByte |= 0x04
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
publicFlagByte |= 0x00
case protocol.PacketNumberLen2:
publicFlagByte |= 0x10
case protocol.PacketNumberLen4:
publicFlagByte |= 0x20
}
b.WriteByte(publicFlagByte)
if h.DestConnectionID.Len() > 0 {
b.Write(h.DestConnectionID)
}
if h.VersionFlag && pers == protocol.PerspectiveClient {
utils.BigEndian.WriteUint32(b, uint32(h.Version))
}
if len(h.DiversificationNonce) > 0 {
b.Write(h.DiversificationNonce)
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(h.PacketNumber))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(h.PacketNumber))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber))
case protocol.PacketNumberLen6:
return errInvalidPacketNumberLen
default:
return errors.New("PublicHeader: PacketNumberLen not set")
}
return nil
// ParseExtended parses the version dependent part of the header.
// The Reader has to be set such that it points to the first byte of the header.
func (h *Header) ParseExtended(b *bytes.Reader, ver protocol.VersionNumber) (*ExtendedHeader, error) {
return h.toExtendedHeader().parse(b, ver)
}
// GetLength determines the length of the Header.
func (h *Header) GetLength(v protocol.VersionNumber) (protocol.ByteCount, error) {
if !v.UsesIETFHeaderFormat() {
return h.getPublicHeaderLength()
}
return h.getHeaderLength(v)
}
func (h *Header) getHeaderLength(v protocol.VersionNumber) (protocol.ByteCount, error) {
if h.IsLongHeader {
length := 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol.ByteCount(h.DestConnectionID.Len()+h.SrcConnectionID.Len()) + protocol.ByteCount(h.PacketNumberLen)
if v.UsesLengthInHeader() {
length += utils.VarIntLen(uint64(h.PayloadLen))
}
if h.Type == protocol.PacketTypeInitial && v.UsesTokenInHeader() {
length += utils.VarIntLen(uint64(len(h.Token))) + protocol.ByteCount(len(h.Token))
}
if h.Type == protocol.PacketType0RTT && v == protocol.Version44 {
length += protocol.ByteCount(len(h.DiversificationNonce))
}
return length, nil
}
length := protocol.ByteCount(1 /* type byte */ + h.DestConnectionID.Len())
if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 {
return 0, fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen)
}
length += protocol.ByteCount(h.PacketNumberLen)
return length, nil
}
// getPublicHeaderLength gets the length of the publicHeader in bytes.
// It can only be called for regular packets.
func (h *Header) getPublicHeaderLength() (protocol.ByteCount, error) {
length := protocol.ByteCount(1) // 1 byte for public flags
if h.PacketNumberLen == protocol.PacketNumberLen6 {
return 0, errInvalidPacketNumberLen
}
if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 {
return 0, errPacketNumberLenNotSet
}
length += protocol.ByteCount(h.PacketNumberLen)
length += protocol.ByteCount(h.DestConnectionID.Len())
// Version Number in packets sent by the client
if h.VersionFlag {
length += 4
}
length += protocol.ByteCount(len(h.DiversificationNonce))
return length, nil
}
// Log logs the Header
func (h *Header) Log(logger utils.Logger) {
if h.IsPublicHeader {
h.logPublicHeader(logger)
} else {
h.logHeader(logger)
}
}
func (h *Header) logHeader(logger utils.Logger) {
if h.IsLongHeader {
if h.Version == 0 {
logger.Debugf("\tVersionNegotiationPacket{DestConnectionID: %s, SrcConnectionID: %s, SupportedVersions: %s}", h.DestConnectionID, h.SrcConnectionID, h.SupportedVersions)
} else {
var token string
if h.Type == protocol.PacketTypeInitial || h.Type == protocol.PacketTypeRetry {
if len(h.Token) == 0 {
token = "Token: (empty), "
} else {
token = fmt.Sprintf("Token: %#x, ", h.Token)
}
}
if h.Type == protocol.PacketTypeRetry {
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sOrigDestConnectionID: %s, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.OrigDestConnectionID, h.Version)
return
}
if h.Version == protocol.Version44 {
var divNonce string
if h.Type == protocol.PacketType0RTT {
divNonce = fmt.Sprintf("Diversification Nonce: %#x, ", h.DiversificationNonce)
}
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, %sVersion: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, h.PacketNumber, h.PacketNumberLen, divNonce, h.Version)
return
}
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, %sPacketNumber: %#x, PacketNumberLen: %d, PayloadLen: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, token, h.PacketNumber, h.PacketNumberLen, h.PayloadLen, h.Version)
}
} else {
logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, h.KeyPhase)
}
}
func (h *Header) logPublicHeader(logger utils.Logger) {
ver := "(unset)"
if h.Version != 0 {
ver = h.Version.String()
}
logger.Debugf("\tPublic Header{ConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, Version: %s, DiversificationNonce: %#v}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, ver, h.DiversificationNonce)
}
func encodeConnIDLen(dest, src protocol.ConnectionID) (byte, error) {
dcil, err := encodeSingleConnIDLen(dest)
if err != nil {
return 0, err
}
scil, err := encodeSingleConnIDLen(src)
if err != nil {
return 0, err
}
return scil | dcil<<4, nil
}
func encodeSingleConnIDLen(id protocol.ConnectionID) (byte, error) {
len := id.Len()
if len == 0 {
return 0, nil
}
if len < 4 || len > 18 {
return 0, fmt.Errorf("invalid connection ID length: %d bytes", len)
}
return byte(len - 3), nil
func (h *Header) toExtendedHeader() *ExtendedHeader {
return &ExtendedHeader{Header: *h}
}
func decodeConnIDLen(enc byte) (int /*dest conn id len*/, int /*src conn id len*/) {

View File

@@ -1,273 +0,0 @@
package wire
import (
"bytes"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// The InvariantHeader is the version independent part of the header
type InvariantHeader struct {
IsLongHeader bool
Version protocol.VersionNumber
SrcConnectionID protocol.ConnectionID
DestConnectionID protocol.ConnectionID
typeByte byte
}
// ParseInvariantHeader parses the version independent part of the header
func ParseInvariantHeader(b *bytes.Reader, shortHeaderConnIDLen int) (*InvariantHeader, error) {
typeByte, err := b.ReadByte()
if err != nil {
return nil, err
}
h := &InvariantHeader{typeByte: typeByte}
h.IsLongHeader = typeByte&0x80 > 0
// If this is not a Long Header, it could either be a Public Header or a Short Header.
if !h.IsLongHeader {
// In the Public Header 0x8 is the Connection ID Flag.
// In the IETF Short Header:
// * 0x8 it is the gQUIC Demultiplexing bit, and always 0.
// * 0x20 and 0x10 are always 1.
var connIDLen int
if typeByte&0x8 > 0 { // Public Header containing a connection ID
connIDLen = 8
}
if typeByte&0x38 == 0x30 { // Short Header
connIDLen = shortHeaderConnIDLen
}
if connIDLen > 0 {
h.DestConnectionID, err = protocol.ReadConnectionID(b, connIDLen)
if err != nil {
return nil, err
}
}
return h, nil
}
// Long Header
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h.Version = protocol.VersionNumber(v)
connIDLenByte, err := b.ReadByte()
if err != nil {
return nil, err
}
dcil, scil := decodeConnIDLen(connIDLenByte)
h.DestConnectionID, err = protocol.ReadConnectionID(b, dcil)
if err != nil {
return nil, err
}
h.SrcConnectionID, err = protocol.ReadConnectionID(b, scil)
if err != nil {
return nil, err
}
return h, nil
}
// Parse parses the version dependent part of the header
func (iv *InvariantHeader) Parse(b *bytes.Reader, sentBy protocol.Perspective, ver protocol.VersionNumber) (*Header, error) {
if iv.IsLongHeader {
if iv.Version == 0 { // Version Negotiation Packet
return iv.parseVersionNegotiationPacket(b)
}
return iv.parseLongHeader(b, sentBy, ver)
}
// The Public Header never uses 6 byte packet numbers.
// Therefore, the third and fourth bit will never be 11.
// For the Short Header, the third and fourth bit are always 11.
if iv.typeByte&0x30 != 0x30 {
if sentBy == protocol.PerspectiveServer && iv.typeByte&0x1 > 0 {
return iv.parseVersionNegotiationPacket(b)
}
return iv.parsePublicHeader(b, sentBy, ver)
}
return iv.parseShortHeader(b, ver)
}
func (iv *InvariantHeader) toHeader() *Header {
return &Header{
IsLongHeader: iv.IsLongHeader,
DestConnectionID: iv.DestConnectionID,
SrcConnectionID: iv.SrcConnectionID,
Version: iv.Version,
}
}
func (iv *InvariantHeader) parseVersionNegotiationPacket(b *bytes.Reader) (*Header, error) {
h := iv.toHeader()
h.VersionFlag = true
if b.Len() == 0 {
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list")
}
h.IsVersionNegotiation = true
h.SupportedVersions = make([]protocol.VersionNumber, b.Len()/4)
for i := 0; b.Len() > 0; i++ {
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, qerr.InvalidVersionNegotiationPacket
}
h.SupportedVersions[i] = protocol.VersionNumber(v)
}
return h, nil
}
func (iv *InvariantHeader) parseLongHeader(b *bytes.Reader, sentBy protocol.Perspective, v protocol.VersionNumber) (*Header, error) {
h := iv.toHeader()
h.Type = protocol.PacketType(iv.typeByte & 0x7f)
if h.Type != protocol.PacketTypeInitial && h.Type != protocol.PacketTypeRetry && h.Type != protocol.PacketType0RTT && h.Type != protocol.PacketTypeHandshake {
return nil, qerr.Error(qerr.InvalidPacketHeader, fmt.Sprintf("Received packet with invalid packet type: %d", h.Type))
}
if h.Type == protocol.PacketTypeRetry {
odcilByte, err := b.ReadByte()
if err != nil {
return nil, err
}
odcil := decodeSingleConnIDLen(odcilByte & 0xf)
h.OrigDestConnectionID, err = protocol.ReadConnectionID(b, odcil)
if err != nil {
return nil, err
}
h.Token = make([]byte, b.Len())
if _, err := io.ReadFull(b, h.Token); err != nil {
return nil, err
}
return h, nil
}
if h.Type == protocol.PacketTypeInitial && v.UsesTokenInHeader() {
tokenLen, err := utils.ReadVarInt(b)
if err != nil {
return nil, err
}
if tokenLen > uint64(b.Len()) {
return nil, io.EOF
}
h.Token = make([]byte, tokenLen)
if _, err := io.ReadFull(b, h.Token); err != nil {
return nil, err
}
}
if v.UsesLengthInHeader() {
pl, err := utils.ReadVarInt(b)
if err != nil {
return nil, err
}
h.PayloadLen = protocol.ByteCount(pl)
}
if v.UsesVarintPacketNumbers() {
pn, pnLen, err := utils.ReadVarIntPacketNumber(b)
if err != nil {
return nil, err
}
h.PacketNumber = pn
h.PacketNumberLen = pnLen
} else {
pn, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h.PacketNumber = protocol.PacketNumber(pn)
h.PacketNumberLen = protocol.PacketNumberLen4
}
if h.Type == protocol.PacketType0RTT && v == protocol.Version44 && sentBy == protocol.PerspectiveServer {
h.DiversificationNonce = make([]byte, 32)
if _, err := io.ReadFull(b, h.DiversificationNonce); err != nil {
if err == io.ErrUnexpectedEOF {
return nil, io.EOF
}
return nil, err
}
}
return h, nil
}
func (iv *InvariantHeader) parseShortHeader(b *bytes.Reader, v protocol.VersionNumber) (*Header, error) {
h := iv.toHeader()
h.KeyPhase = int(iv.typeByte&0x40) >> 6
if v.UsesVarintPacketNumbers() {
pn, pnLen, err := utils.ReadVarIntPacketNumber(b)
if err != nil {
return nil, err
}
h.PacketNumber = pn
h.PacketNumberLen = pnLen
} else {
switch iv.typeByte & 0x3 {
case 0x0:
h.PacketNumberLen = protocol.PacketNumberLen1
case 0x1:
h.PacketNumberLen = protocol.PacketNumberLen2
case 0x2:
h.PacketNumberLen = protocol.PacketNumberLen4
default:
return nil, errInvalidPacketNumberLen
}
p, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen))
if err != nil {
return nil, err
}
h.PacketNumber = protocol.PacketNumber(p)
}
return h, nil
}
func (iv *InvariantHeader) parsePublicHeader(b *bytes.Reader, sentBy protocol.Perspective, ver protocol.VersionNumber) (*Header, error) {
h := iv.toHeader()
h.IsPublicHeader = true
h.ResetFlag = iv.typeByte&0x2 > 0
if h.ResetFlag {
return h, nil
}
h.VersionFlag = iv.typeByte&0x1 > 0
if h.VersionFlag && sentBy == protocol.PerspectiveClient {
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h.Version = protocol.VersionNumber(v)
}
// Contrary to what the gQUIC wire spec says, the 0x4 bit only indicates the presence of the diversification nonce for packets sent by the server.
// It doesn't have any meaning when sent by the client.
if sentBy == protocol.PerspectiveServer && iv.typeByte&0x4 > 0 {
h.DiversificationNonce = make([]byte, 32)
if _, err := io.ReadFull(b, h.DiversificationNonce); err != nil {
if err == io.ErrUnexpectedEOF {
return nil, io.EOF
}
return nil, err
}
}
switch iv.typeByte & 0x30 {
case 0x00:
h.PacketNumberLen = protocol.PacketNumberLen1
case 0x10:
h.PacketNumberLen = protocol.PacketNumberLen2
case 0x20:
h.PacketNumberLen = protocol.PacketNumberLen4
}
pn, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen))
if err != nil {
return nil, err
}
h.PacketNumber = protocol.PacketNumber(pn)
return h, nil
}

View File

@@ -11,3 +11,9 @@ type Frame interface {
Write(b *bytes.Buffer, version protocol.VersionNumber) error
Length(version protocol.VersionNumber) protocol.ByteCount
}
// A FrameParser parses QUIC frames, one by one.
type FrameParser interface {
ParseNext(*bytes.Reader, protocol.EncryptionLevel) (Frame, error)
SetAckDelayExponent(uint8)
}

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"strings"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
@@ -17,14 +18,11 @@ func LogFrame(logger utils.Logger, frame Frame, sent bool) {
dir = "->"
}
switch f := frame.(type) {
case *CryptoFrame:
dataLen := protocol.ByteCount(len(f.Data))
logger.Debugf("\t%s &wire.CryptoFrame{Offset: 0x%x, Data length: 0x%x, Offset + Data length: 0x%x}", dir, f.Offset, dataLen, f.Offset+dataLen)
case *StreamFrame:
logger.Debugf("\t%s &wire.StreamFrame{StreamID: %d, FinBit: %t, Offset: 0x%x, Data length: 0x%x, Offset + Data length: 0x%x}", dir, f.StreamID, f.FinBit, f.Offset, f.DataLen(), f.Offset+f.DataLen())
case *StopWaitingFrame:
if sent {
logger.Debugf("\t%s &wire.StopWaitingFrame{LeastUnacked: 0x%x, PacketNumberLen: 0x%x}", dir, f.LeastUnacked, f.PacketNumberLen)
} else {
logger.Debugf("\t%s &wire.StopWaitingFrame{LeastUnacked: 0x%x}", dir, f.LeastUnacked)
}
case *AckFrame:
if len(f.AckRanges) > 1 {
ackRanges := make([]string, len(f.AckRanges))
@@ -35,6 +33,10 @@ func LogFrame(logger utils.Logger, frame Frame, sent bool) {
} else {
logger.Debugf("\t%s &wire.AckFrame{LargestAcked: %#x, LowestAcked: %#x, DelayTime: %s}", dir, f.LargestAcked(), f.LowestAcked(), f.DelayTime.String())
}
case *NewConnectionIDFrame:
logger.Debugf("\t%s &wire.NewConnectionIDFrame{SequenceNumber: %d, ConnectionID: %s, StatelessResetToken: %#x}", dir, f.SequenceNumber, f.ConnectionID, f.StatelessResetToken)
case *NewTokenFrame:
logger.Debugf("\t%s &wire.NewTokenFrame{Token: %#x}", dir, f.Token)
default:
logger.Debugf("\t%s %#v", dir, frame)
}

View File

@@ -14,7 +14,6 @@ type MaxDataFrame struct {
// parseMaxDataFrame parses a MAX_DATA frame
func parseMaxDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxDataFrame, error) {
// read the TypeByte
if _, err := r.ReadByte(); err != nil {
return nil, err
}
@@ -30,22 +29,12 @@ func parseMaxDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxDat
//Write writes a MAX_STREAM_DATA frame
func (f *MaxDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
if !version.UsesIETFFrameFormat() {
// write a gQUIC WINDOW_UPDATE frame (with stream ID 0, which means connection-level there)
return (&windowUpdateFrame{
StreamID: 0,
ByteOffset: f.ByteOffset,
}).Write(b, version)
}
b.WriteByte(0x4)
b.WriteByte(0x10)
utils.WriteVarInt(b, uint64(f.ByteOffset))
return nil
}
// Length of a written frame
func (f *MaxDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() { // writing this frame would result in a gQUIC WINDOW_UPDATE being written, which is longer
return 1 + 4 + 8
}
return 1 + utils.VarIntLen(uint64(f.ByteOffset))
}

View File

@@ -7,17 +7,13 @@ import (
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A MaxStreamDataFrame carries flow control information for a stream
// A MaxStreamDataFrame is a MAX_STREAM_DATA frame
type MaxStreamDataFrame struct {
StreamID protocol.StreamID
ByteOffset protocol.ByteCount
}
// parseMaxStreamDataFrame parses a MAX_STREAM_DATA frame
func parseMaxStreamDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*MaxStreamDataFrame, error) {
frame := &MaxStreamDataFrame{}
// read the TypeByte
if _, err := r.ReadByte(); err != nil {
return nil, err
}
@@ -26,25 +22,19 @@ func parseMaxStreamDataFrame(r *bytes.Reader, version protocol.VersionNumber) (*
if err != nil {
return nil, err
}
frame.StreamID = protocol.StreamID(sid)
byteOffset, err := utils.ReadVarInt(r)
offset, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
frame.ByteOffset = protocol.ByteCount(byteOffset)
return frame, nil
return &MaxStreamDataFrame{
StreamID: protocol.StreamID(sid),
ByteOffset: protocol.ByteCount(offset),
}, nil
}
// Write writes a MAX_STREAM_DATA frame
func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
if !version.UsesIETFFrameFormat() {
return (&windowUpdateFrame{
StreamID: f.StreamID,
ByteOffset: f.ByteOffset,
}).Write(b, version)
}
b.WriteByte(0x5)
b.WriteByte(0x11)
utils.WriteVarInt(b, uint64(f.StreamID))
utils.WriteVarInt(b, uint64(f.ByteOffset))
return nil
@@ -52,9 +42,5 @@ func (f *MaxStreamDataFrame) Write(b *bytes.Buffer, version protocol.VersionNumb
// Length of a written frame
func (f *MaxStreamDataFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
// writing this frame would result in a gQUIC WINDOW_UPDATE being written, which has a different length
if !version.UsesIETFFrameFormat() {
return 1 + 4 + 8
}
return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.ByteOffset))
}

View File

@@ -1,37 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A MaxStreamIDFrame is a MAX_STREAM_ID frame
type MaxStreamIDFrame struct {
StreamID protocol.StreamID
}
// parseMaxStreamIDFrame parses a MAX_STREAM_ID frame
func parseMaxStreamIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStreamIDFrame, error) {
// read the Type byte
if _, err := r.ReadByte(); err != nil {
return nil, err
}
streamID, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &MaxStreamIDFrame{StreamID: protocol.StreamID(streamID)}, nil
}
func (f *MaxStreamIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x6)
utils.WriteVarInt(b, uint64(f.StreamID))
return nil
}
// Length of a written frame
func (f *MaxStreamIDFrame) Length(protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID))
}

View File

@@ -0,0 +1,51 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A MaxStreamsFrame is a MAX_STREAMS frame
type MaxStreamsFrame struct {
Type protocol.StreamType
MaxStreams uint64
}
func parseMaxStreamsFrame(r *bytes.Reader, _ protocol.VersionNumber) (*MaxStreamsFrame, error) {
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
f := &MaxStreamsFrame{}
switch typeByte {
case 0x12:
f.Type = protocol.StreamTypeBidi
case 0x13:
f.Type = protocol.StreamTypeUni
}
streamID, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
f.MaxStreams = streamID
return f, nil
}
func (f *MaxStreamsFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
switch f.Type {
case protocol.StreamTypeBidi:
b.WriteByte(0x12)
case protocol.StreamTypeUni:
b.WriteByte(0x13)
}
utils.WriteVarInt(b, f.MaxStreams)
return nil
}
// Length of a written frame
func (f *MaxStreamsFrame) Length(protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(f.MaxStreams)
}

View File

@@ -0,0 +1,70 @@
package wire
import (
"bytes"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/protocol"
)
// A NewConnectionIDFrame is a NEW_CONNECTION_ID frame
type NewConnectionIDFrame struct {
SequenceNumber uint64
ConnectionID protocol.ConnectionID
StatelessResetToken [16]byte
}
func parseNewConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewConnectionIDFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
seq, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
connIDLen, err := r.ReadByte()
if err != nil {
return nil, err
}
if connIDLen < 4 || connIDLen > 18 {
return nil, fmt.Errorf("invalid connection ID length: %d", connIDLen)
}
connID, err := protocol.ReadConnectionID(r, int(connIDLen))
if err != nil {
return nil, err
}
frame := &NewConnectionIDFrame{
SequenceNumber: seq,
ConnectionID: connID,
}
if _, err := io.ReadFull(r, frame.StatelessResetToken[:]); err != nil {
if err == io.ErrUnexpectedEOF {
return nil, io.EOF
}
return nil, err
}
return frame, nil
}
func (f *NewConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x18)
utils.WriteVarInt(b, f.SequenceNumber)
connIDLen := f.ConnectionID.Len()
if connIDLen < 4 || connIDLen > 18 {
return fmt.Errorf("invalid connection ID length: %d", connIDLen)
}
b.WriteByte(uint8(connIDLen))
b.Write(f.ConnectionID.Bytes())
b.Write(f.StatelessResetToken[:])
return nil
}
// Length of a written frame
func (f *NewConnectionIDFrame) Length(protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(f.SequenceNumber) + 1 /* connection ID length */ + protocol.ByteCount(f.ConnectionID.Len()) + 16
}

View File

@@ -0,0 +1,44 @@
package wire
import (
"bytes"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A NewTokenFrame is a NEW_TOKEN frame
type NewTokenFrame struct {
Token []byte
}
func parseNewTokenFrame(r *bytes.Reader, _ protocol.VersionNumber) (*NewTokenFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
tokenLen, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
if uint64(r.Len()) < tokenLen {
return nil, io.EOF
}
token := make([]byte, int(tokenLen))
if _, err := io.ReadFull(r, token); err != nil {
return nil, err
}
return &NewTokenFrame{Token: token}, nil
}
func (f *NewTokenFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x7)
utils.WriteVarInt(b, uint64(len(f.Token)))
b.Write(f.Token)
return nil
}
// Length of a written frame
func (f *NewTokenFrame) Length(protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(len(f.Token))) + protocol.ByteCount(len(f.Token))
}

View File

@@ -27,8 +27,7 @@ func parsePathChallengeFrame(r *bytes.Reader, version protocol.VersionNumber) (*
}
func (f *PathChallengeFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
typeByte := uint8(0x0e)
b.WriteByte(typeByte)
b.WriteByte(0x1a)
b.Write(f.Data[:])
return nil
}

View File

@@ -27,8 +27,7 @@ func parsePathResponseFrame(r *bytes.Reader, version protocol.VersionNumber) (*P
}
func (f *PathResponseFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
typeByte := uint8(0x0f)
b.WriteByte(typeByte)
b.WriteByte(0x1b)
b.Write(f.Data[:])
return nil
}

View File

@@ -6,24 +6,18 @@ import (
"github.com/lucas-clemente/quic-go/internal/protocol"
)
// A PingFrame is a ping frame
// A PingFrame is a PING frame
type PingFrame struct{}
// parsePingFrame parses a Ping frame
func parsePingFrame(r *bytes.Reader, version protocol.VersionNumber) (*PingFrame, error) {
frame := &PingFrame{}
_, err := r.ReadByte()
if err != nil {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
return frame, nil
return &PingFrame{}, nil
}
func (f *PingFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
typeByte := uint8(0x07)
b.WriteByte(typeByte)
b.WriteByte(0x1)
return nil
}

View File

@@ -1,65 +0,0 @@
package wire
import (
"bytes"
"encoding/binary"
"errors"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A PublicReset is a PUBLIC_RESET
type PublicReset struct {
RejectedPacketNumber protocol.PacketNumber
Nonce uint64
}
// WritePublicReset writes a PUBLIC_RESET
func WritePublicReset(connectionID protocol.ConnectionID, rejectedPacketNumber protocol.PacketNumber, nonceProof uint64) []byte {
b := &bytes.Buffer{}
b.WriteByte(0x0a)
b.Write(connectionID)
utils.LittleEndian.WriteUint32(b, uint32(handshake.TagPRST))
utils.LittleEndian.WriteUint32(b, 2)
utils.LittleEndian.WriteUint32(b, uint32(handshake.TagRNON))
utils.LittleEndian.WriteUint32(b, 8)
utils.LittleEndian.WriteUint32(b, uint32(handshake.TagRSEQ))
utils.LittleEndian.WriteUint32(b, 16)
utils.LittleEndian.WriteUint64(b, nonceProof)
utils.LittleEndian.WriteUint64(b, uint64(rejectedPacketNumber))
return b.Bytes()
}
// ParsePublicReset parses a PUBLIC_RESET
func ParsePublicReset(r *bytes.Reader) (*PublicReset, error) {
pr := PublicReset{}
msg, err := handshake.ParseHandshakeMessage(r)
if err != nil {
return nil, err
}
if msg.Tag != handshake.TagPRST {
return nil, errors.New("wrong public reset tag")
}
// The RSEQ tag is mandatory according to the gQUIC wire spec.
// However, Google doesn't send RSEQ in their PUBLIC_RESETs.
// Therefore, we'll treat RSEQ as an optional field.
if rseq, ok := msg.Data[handshake.TagRSEQ]; ok {
if len(rseq) != 8 {
return nil, errors.New("invalid RSEQ tag")
}
pr.RejectedPacketNumber = protocol.PacketNumber(binary.LittleEndian.Uint64(rseq))
}
rnon, ok := msg.Data[handshake.TagRNON]
if !ok {
return nil, errors.New("RNON missing")
}
if len(rnon) != 8 {
return nil, errors.New("invalid RNON tag")
}
pr.Nonce = binary.LittleEndian.Uint64(rnon)
return &pr, nil
}

View File

@@ -0,0 +1,58 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A ResetStreamFrame is a RESET_STREAM frame in QUIC
type ResetStreamFrame struct {
StreamID protocol.StreamID
ErrorCode protocol.ApplicationErrorCode
ByteOffset protocol.ByteCount
}
func parseResetStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*ResetStreamFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
var streamID protocol.StreamID
var errorCode uint16
var byteOffset protocol.ByteCount
sid, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
streamID = protocol.StreamID(sid)
errorCode, err = utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
bo, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
byteOffset = protocol.ByteCount(bo)
return &ResetStreamFrame{
StreamID: streamID,
ErrorCode: protocol.ApplicationErrorCode(errorCode),
ByteOffset: byteOffset,
}, nil
}
func (f *ResetStreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
b.WriteByte(0x4)
utils.WriteVarInt(b, uint64(f.StreamID))
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
utils.WriteVarInt(b, uint64(f.ByteOffset))
return nil
}
// Length of a written frame
func (f *ResetStreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 + utils.VarIntLen(uint64(f.ByteOffset))
}

View File

@@ -0,0 +1,36 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A RetireConnectionIDFrame is a RETIRE_CONNECTION_ID frame
type RetireConnectionIDFrame struct {
SequenceNumber uint64
}
func parseRetireConnectionIDFrame(r *bytes.Reader, _ protocol.VersionNumber) (*RetireConnectionIDFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
seq, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &RetireConnectionIDFrame{SequenceNumber: seq}, nil
}
func (f *RetireConnectionIDFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x19)
utils.WriteVarInt(b, f.SequenceNumber)
return nil
}
// Length of a written frame
func (f *RetireConnectionIDFrame) Length(protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(f.SequenceNumber)
}

View File

@@ -1,89 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A RstStreamFrame is a RST_STREAM frame in QUIC
type RstStreamFrame struct {
StreamID protocol.StreamID
// The error code is a uint32 in gQUIC, but a uint16 in IETF QUIC.
// protocol.ApplicaitonErrorCode is a uint16, so larger values in gQUIC frames will be truncated.
ErrorCode protocol.ApplicationErrorCode
ByteOffset protocol.ByteCount
}
// parseRstStreamFrame parses a RST_STREAM frame
func parseRstStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*RstStreamFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
var streamID protocol.StreamID
var errorCode uint16
var byteOffset protocol.ByteCount
if version.UsesIETFFrameFormat() {
sid, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
streamID = protocol.StreamID(sid)
errorCode, err = utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
bo, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
byteOffset = protocol.ByteCount(bo)
} else {
sid, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
streamID = protocol.StreamID(sid)
bo, err := utils.BigEndian.ReadUint64(r)
if err != nil {
return nil, err
}
byteOffset = protocol.ByteCount(bo)
ec, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
errorCode = uint16(ec)
}
return &RstStreamFrame{
StreamID: streamID,
ErrorCode: protocol.ApplicationErrorCode(errorCode),
ByteOffset: byteOffset,
}, nil
}
//Write writes a RST_STREAM frame
func (f *RstStreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
b.WriteByte(0x01)
if version.UsesIETFFrameFormat() {
utils.WriteVarInt(b, uint64(f.StreamID))
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
utils.WriteVarInt(b, uint64(f.ByteOffset))
} else {
utils.BigEndian.WriteUint32(b, uint32(f.StreamID))
utils.BigEndian.WriteUint64(b, uint64(f.ByteOffset))
utils.BigEndian.WriteUint32(b, uint32(f.ErrorCode))
}
return nil
}
// Length of a written frame
func (f *RstStreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if version.UsesIETFFrameFormat() {
return 1 + utils.VarIntLen(uint64(f.StreamID)) + 2 + utils.VarIntLen(uint64(f.ByteOffset))
}
return 1 + 4 + 8 + 4
}

View File

@@ -15,7 +15,7 @@ type StopSendingFrame struct {
// parseStopSendingFrame parses a STOP_SENDING frame
func parseStopSendingFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StopSendingFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
if _, err := r.ReadByte(); err != nil {
return nil, err
}
@@ -40,7 +40,7 @@ func (f *StopSendingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
}
func (f *StopSendingFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x0c)
b.WriteByte(0x5)
utils.WriteVarInt(b, uint64(f.StreamID))
utils.BigEndian.WriteUint16(b, uint16(f.ErrorCode))
return nil

View File

@@ -1,77 +0,0 @@
package wire
import (
"bytes"
"errors"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A StopWaitingFrame in QUIC
type StopWaitingFrame struct {
LeastUnacked protocol.PacketNumber
PacketNumberLen protocol.PacketNumberLen
// PacketNumber is the packet number of the packet that this StopWaitingFrame will be sent with
PacketNumber protocol.PacketNumber
}
var (
errLeastUnackedHigherThanPacketNumber = errors.New("StopWaitingFrame: LeastUnacked can't be greater than the packet number")
errPacketNumberNotSet = errors.New("StopWaitingFrame: PacketNumber not set")
errPacketNumberLenNotSet = errors.New("StopWaitingFrame: PacketNumberLen not set")
)
func (f *StopWaitingFrame) Write(b *bytes.Buffer, v protocol.VersionNumber) error {
if v.UsesIETFFrameFormat() {
return errors.New("STOP_WAITING not defined in IETF QUIC")
}
// make sure the PacketNumber was set
if f.PacketNumber == protocol.PacketNumber(0) {
return errPacketNumberNotSet
}
if f.LeastUnacked > f.PacketNumber {
return errLeastUnackedHigherThanPacketNumber
}
b.WriteByte(0x06)
leastUnackedDelta := uint64(f.PacketNumber - f.LeastUnacked)
switch f.PacketNumberLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(leastUnackedDelta))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(leastUnackedDelta))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(leastUnackedDelta))
case protocol.PacketNumberLen6:
utils.BigEndian.WriteUint48(b, leastUnackedDelta&(1<<48-1))
default:
return errPacketNumberLenNotSet
}
return nil
}
// Length of a written frame
func (f *StopWaitingFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + protocol.ByteCount(f.PacketNumberLen)
}
// parseStopWaitingFrame parses a StopWaiting frame
func parseStopWaitingFrame(r *bytes.Reader, packetNumber protocol.PacketNumber, packetNumberLen protocol.PacketNumberLen, _ protocol.VersionNumber) (*StopWaitingFrame, error) {
frame := &StopWaitingFrame{}
// read the TypeByte
if _, err := r.ReadByte(); err != nil {
return nil, err
}
leastUnackedDelta, err := utils.BigEndian.ReadUintN(r, uint8(packetNumberLen))
if err != nil {
return nil, err
}
if leastUnackedDelta > uint64(packetNumber) {
return nil, errors.New("invalid LeastUnackedDelta")
}
frame.LeastUnacked = protocol.PacketNumber(uint64(packetNumber) - leastUnackedDelta)
return frame, nil
}

View File

@@ -1,52 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A StreamBlockedFrame in QUIC
type StreamBlockedFrame struct {
StreamID protocol.StreamID
Offset protocol.ByteCount
}
// parseStreamBlockedFrame parses a STREAM_BLOCKED frame
func parseStreamBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamBlockedFrame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
sid, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
offset, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &StreamBlockedFrame{
StreamID: protocol.StreamID(sid),
Offset: protocol.ByteCount(offset),
}, nil
}
// Write writes a STREAM_BLOCKED frame
func (f *StreamBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
if !version.UsesIETFFrameFormat() {
return (&blockedFrameLegacy{StreamID: f.StreamID}).Write(b, version)
}
b.WriteByte(0x09)
utils.WriteVarInt(b, uint64(f.StreamID))
utils.WriteVarInt(b, uint64(f.Offset))
return nil
}
// Length of a written frame
func (f *StreamBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return 1 + 4
}
return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.Offset))
}

View File

@@ -0,0 +1,46 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A StreamDataBlockedFrame is a STREAM_DATA_BLOCKED frame
type StreamDataBlockedFrame struct {
StreamID protocol.StreamID
DataLimit protocol.ByteCount
}
func parseStreamDataBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamDataBlockedFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
sid, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
offset, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &StreamDataBlockedFrame{
StreamID: protocol.StreamID(sid),
DataLimit: protocol.ByteCount(offset),
}, nil
}
func (f *StreamDataBlockedFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
b.WriteByte(0x15)
utils.WriteVarInt(b, uint64(f.StreamID))
utils.WriteVarInt(b, uint64(f.DataLimit))
return nil
}
// Length of a written frame
func (f *StreamDataBlockedFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID)) + utils.VarIntLen(uint64(f.DataLimit))
}

View File

@@ -6,8 +6,8 @@ import (
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/qerr"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// A StreamFrame of QUIC
@@ -19,22 +19,17 @@ type StreamFrame struct {
Data []byte
}
// parseStreamFrame reads a STREAM frame
func parseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamFrame, error) {
if !version.UsesIETFFrameFormat() {
return parseLegacyStreamFrame(r, version)
}
frame := &StreamFrame{}
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
frame.FinBit = typeByte&0x1 > 0
frame.DataLenPresent = typeByte&0x2 > 0
hasOffset := typeByte&0x4 > 0
frame := &StreamFrame{
FinBit: typeByte&0x1 > 0,
DataLenPresent: typeByte&0x2 > 0,
}
streamID, err := utils.ReadVarInt(r)
if err != nil {
@@ -74,22 +69,18 @@ func parseStreamFrame(r *bytes.Reader, version protocol.VersionNumber) (*StreamF
}
}
if frame.Offset+frame.DataLen() > protocol.MaxByteCount {
return nil, qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset")
return nil, qerr.Error(qerr.FrameEncodingError, "stream data overflows maximum offset")
}
return frame, nil
}
// Write writes a STREAM frame
func (f *StreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) error {
if !version.UsesIETFFrameFormat() {
return f.writeLegacy(b, version)
}
if len(f.Data) == 0 && !f.FinBit {
return errors.New("StreamFrame: attempting to write empty frame without FIN")
}
typeByte := byte(0x10)
typeByte := byte(0x8)
if f.FinBit {
typeByte ^= 0x1
}
@@ -114,9 +105,6 @@ func (f *StreamFrame) Write(b *bytes.Buffer, version protocol.VersionNumber) err
// Length returns the total length of the STREAM frame
func (f *StreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return f.lengthLegacy(version)
}
length := 1 + utils.VarIntLen(uint64(f.StreamID))
if f.Offset != 0 {
length += utils.VarIntLen(uint64(f.Offset))
@@ -127,13 +115,14 @@ func (f *StreamFrame) Length(version protocol.VersionNumber) protocol.ByteCount
return length + f.DataLen()
}
// DataLen gives the length of data in bytes
func (f *StreamFrame) DataLen() protocol.ByteCount {
return protocol.ByteCount(len(f.Data))
}
// MaxDataLen returns the maximum data length
// If 0 is returned, writing will fail (a STREAM frame must contain at least 1 byte of data).
func (f *StreamFrame) MaxDataLen(maxSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount {
if !version.UsesIETFFrameFormat() {
return f.maxDataLenLegacy(maxSize, version)
}
headerLen := 1 + utils.VarIntLen(uint64(f.StreamID))
if f.Offset != 0 {
headerLen += utils.VarIntLen(uint64(f.Offset))

View File

@@ -1,209 +0,0 @@
package wire
import (
"bytes"
"errors"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
var (
errInvalidStreamIDLen = errors.New("StreamFrame: Invalid StreamID length")
errInvalidOffsetLen = errors.New("StreamFrame: Invalid offset length")
)
// parseLegacyStreamFrame reads a stream frame. The type byte must not have been read yet.
func parseLegacyStreamFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamFrame, error) {
frame := &StreamFrame{}
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
frame.FinBit = typeByte&0x40 > 0
frame.DataLenPresent = typeByte&0x20 > 0
offsetLen := typeByte & 0x1c >> 2
if offsetLen != 0 {
offsetLen++
}
streamIDLen := typeByte&0x3 + 1
sid, err := utils.BigEndian.ReadUintN(r, streamIDLen)
if err != nil {
return nil, err
}
frame.StreamID = protocol.StreamID(sid)
offset, err := utils.BigEndian.ReadUintN(r, offsetLen)
if err != nil {
return nil, err
}
frame.Offset = protocol.ByteCount(offset)
var dataLen uint16
if frame.DataLenPresent {
dataLen, err = utils.BigEndian.ReadUint16(r)
if err != nil {
return nil, err
}
}
// shortcut to prevent the unnecessary allocation of dataLen bytes
// if the dataLen is larger than the remaining length of the packet
// reading the packet contents would result in EOF when attempting to READ
if int(dataLen) > r.Len() {
return nil, io.EOF
}
if !frame.DataLenPresent {
// The rest of the packet is data
dataLen = uint16(r.Len())
}
if dataLen != 0 {
frame.Data = make([]byte, dataLen)
if _, err := io.ReadFull(r, frame.Data); err != nil {
// this should never happen, since we already checked the dataLen earlier
return nil, err
}
}
// MaxByteCount is the highest value that can be encoded with the IETF QUIC variable integer encoding (2^62-1).
// Note that this value is smaller than the maximum value that could be encoded in the gQUIC STREAM frame (2^64-1).
if frame.Offset+frame.DataLen() > protocol.MaxByteCount {
return nil, qerr.Error(qerr.InvalidStreamData, "data overflows maximum offset")
}
if !frame.FinBit && frame.DataLen() == 0 {
return nil, qerr.EmptyStreamFrameNoFin
}
return frame, nil
}
// writeLegacy writes a stream frame.
func (f *StreamFrame) writeLegacy(b *bytes.Buffer, _ protocol.VersionNumber) error {
if len(f.Data) == 0 && !f.FinBit {
return errors.New("StreamFrame: attempting to write empty frame without FIN")
}
typeByte := uint8(0x80) // sets the leftmost bit to 1
if f.FinBit {
typeByte ^= 0x40
}
if f.DataLenPresent {
typeByte ^= 0x20
}
offsetLength := f.getOffsetLength()
if offsetLength > 0 {
typeByte ^= (uint8(offsetLength) - 1) << 2
}
streamIDLen := f.calculateStreamIDLength()
typeByte ^= streamIDLen - 1
b.WriteByte(typeByte)
switch streamIDLen {
case 1:
b.WriteByte(uint8(f.StreamID))
case 2:
utils.BigEndian.WriteUint16(b, uint16(f.StreamID))
case 3:
utils.BigEndian.WriteUint24(b, uint32(f.StreamID))
case 4:
utils.BigEndian.WriteUint32(b, uint32(f.StreamID))
default:
return errInvalidStreamIDLen
}
switch offsetLength {
case 0:
case 2:
utils.BigEndian.WriteUint16(b, uint16(f.Offset))
case 3:
utils.BigEndian.WriteUint24(b, uint32(f.Offset))
case 4:
utils.BigEndian.WriteUint32(b, uint32(f.Offset))
case 5:
utils.BigEndian.WriteUint40(b, uint64(f.Offset))
case 6:
utils.BigEndian.WriteUint48(b, uint64(f.Offset))
case 7:
utils.BigEndian.WriteUint56(b, uint64(f.Offset))
case 8:
utils.BigEndian.WriteUint64(b, uint64(f.Offset))
default:
return errInvalidOffsetLen
}
if f.DataLenPresent {
utils.BigEndian.WriteUint16(b, uint16(len(f.Data)))
}
b.Write(f.Data)
return nil
}
func (f *StreamFrame) calculateStreamIDLength() uint8 {
if f.StreamID < (1 << 8) {
return 1
} else if f.StreamID < (1 << 16) {
return 2
} else if f.StreamID < (1 << 24) {
return 3
}
return 4
}
func (f *StreamFrame) getOffsetLength() protocol.ByteCount {
if f.Offset == 0 {
return 0
}
if f.Offset < (1 << 16) {
return 2
}
if f.Offset < (1 << 24) {
return 3
}
if f.Offset < (1 << 32) {
return 4
}
if f.Offset < (1 << 40) {
return 5
}
if f.Offset < (1 << 48) {
return 6
}
if f.Offset < (1 << 56) {
return 7
}
return 8
}
func (f *StreamFrame) headerLengthLegacy(_ protocol.VersionNumber) protocol.ByteCount {
length := protocol.ByteCount(1) + protocol.ByteCount(f.calculateStreamIDLength()) + f.getOffsetLength()
if f.DataLenPresent {
length += 2
}
return length
}
func (f *StreamFrame) lengthLegacy(version protocol.VersionNumber) protocol.ByteCount {
return f.headerLengthLegacy(version) + f.DataLen()
}
func (f *StreamFrame) maxDataLenLegacy(maxFrameSize protocol.ByteCount, version protocol.VersionNumber) protocol.ByteCount {
headerLen := f.headerLengthLegacy(version)
if headerLen > maxFrameSize {
return 0
}
return maxFrameSize - headerLen
}
// DataLen gives the length of data in bytes
func (f *StreamFrame) DataLen() protocol.ByteCount {
return protocol.ByteCount(len(f.Data))
}

View File

@@ -1,37 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A StreamIDBlockedFrame is a STREAM_ID_BLOCKED frame
type StreamIDBlockedFrame struct {
StreamID protocol.StreamID
}
// parseStreamIDBlockedFrame parses a STREAM_ID_BLOCKED frame
func parseStreamIDBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamIDBlockedFrame, error) {
if _, err := r.ReadByte(); err != nil {
return nil, err
}
streamID, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
return &StreamIDBlockedFrame{StreamID: protocol.StreamID(streamID)}, nil
}
func (f *StreamIDBlockedFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
typeByte := uint8(0x0a)
b.WriteByte(typeByte)
utils.WriteVarInt(b, uint64(f.StreamID))
return nil
}
// Length of a written frame
func (f *StreamIDBlockedFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(uint64(f.StreamID))
}

View File

@@ -0,0 +1,52 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
// A StreamsBlockedFrame is a STREAMS_BLOCKED frame
type StreamsBlockedFrame struct {
Type protocol.StreamType
StreamLimit uint64
}
func parseStreamsBlockedFrame(r *bytes.Reader, _ protocol.VersionNumber) (*StreamsBlockedFrame, error) {
typeByte, err := r.ReadByte()
if err != nil {
return nil, err
}
f := &StreamsBlockedFrame{}
switch typeByte {
case 0x16:
f.Type = protocol.StreamTypeBidi
case 0x17:
f.Type = protocol.StreamTypeUni
}
streamLimit, err := utils.ReadVarInt(r)
if err != nil {
return nil, err
}
f.StreamLimit = streamLimit
return f, nil
}
func (f *StreamsBlockedFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
switch f.Type {
case protocol.StreamTypeBidi:
b.WriteByte(0x16)
case protocol.StreamTypeUni:
b.WriteByte(0x17)
}
utils.WriteVarInt(b, f.StreamLimit)
return nil
}
// Length of a written frame
func (f *StreamsBlockedFrame) Length(_ protocol.VersionNumber) protocol.ByteCount {
return 1 + utils.VarIntLen(f.StreamLimit)
}

View File

@@ -8,25 +8,14 @@ import (
"github.com/lucas-clemente/quic-go/internal/utils"
)
// ComposeGQUICVersionNegotiation composes a Version Negotiation Packet for gQUIC
func ComposeGQUICVersionNegotiation(connID protocol.ConnectionID, versions []protocol.VersionNumber) []byte {
buf := bytes.NewBuffer(make([]byte, 0, 1+8+len(versions)*4))
buf.Write([]byte{0x1 | 0x8}) // type byte
buf.Write(connID)
for _, v := range versions {
utils.BigEndian.WriteUint32(buf, uint32(v))
}
return buf.Bytes()
}
// ComposeVersionNegotiation composes a Version Negotiation according to the IETF draft
// ComposeVersionNegotiation composes a Version Negotiation
func ComposeVersionNegotiation(destConnID, srcConnID protocol.ConnectionID, versions []protocol.VersionNumber) ([]byte, error) {
greasedVersions := protocol.GetGreasedVersions(versions)
expectedLen := 1 /* type byte */ + 4 /* version field */ + 1 /* connection ID length field */ + destConnID.Len() + srcConnID.Len() + len(greasedVersions)*4
buf := bytes.NewBuffer(make([]byte, 0, expectedLen))
r := make([]byte, 1)
_, _ = rand.Read(r) // ignore the error here. It is not critical to have perfect random here.
buf.WriteByte(r[0] | 0x80)
buf.WriteByte(r[0] | 0xc0)
utils.BigEndian.WriteUint32(buf, 0) // version 0
connIDLen, err := encodeConnIDLen(destConnID, srcConnID)
if err != nil {

View File

@@ -1,45 +0,0 @@
package wire
import (
"bytes"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
)
type windowUpdateFrame struct {
StreamID protocol.StreamID
ByteOffset protocol.ByteCount
}
// parseWindowUpdateFrame parses a WINDOW_UPDATE frame
// The frame returned is
// * a MAX_STREAM_DATA frame, if the WINDOW_UPDATE applies to a stream
// * a MAX_DATA frame, if the WINDOW_UPDATE applies to the connection
func parseWindowUpdateFrame(r *bytes.Reader, _ protocol.VersionNumber) (Frame, error) {
if _, err := r.ReadByte(); err != nil { // read the TypeByte
return nil, err
}
streamID, err := utils.BigEndian.ReadUint32(r)
if err != nil {
return nil, err
}
offset, err := utils.BigEndian.ReadUint64(r)
if err != nil {
return nil, err
}
if streamID == 0 {
return &MaxDataFrame{ByteOffset: protocol.ByteCount(offset)}, nil
}
return &MaxStreamDataFrame{
StreamID: protocol.StreamID(streamID),
ByteOffset: protocol.ByteCount(offset),
}, nil
}
func (f *windowUpdateFrame) Write(b *bytes.Buffer, _ protocol.VersionNumber) error {
b.WriteByte(0x4)
utils.BigEndian.WriteUint32(b, uint32(f.StreamID))
utils.BigEndian.WriteUint64(b, uint64(f.ByteOffset))
return nil
}