route/vendor/github.com/lucas-clemente/quic-go/stream_frame_sorter.go

162 lines
3.9 KiB
Go

package quic
import (
"errors"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
)
type streamFrameSorter struct {
queuedFrames map[protocol.ByteCount]*wire.StreamFrame
readPosition protocol.ByteCount
gaps *utils.ByteIntervalList
}
var (
errTooManyGapsInReceivedStreamData = errors.New("Too many gaps in received StreamFrame data")
errDuplicateStreamData = errors.New("Duplicate Stream Data")
errEmptyStreamData = errors.New("Stream Data empty")
)
func newStreamFrameSorter() *streamFrameSorter {
s := streamFrameSorter{
gaps: utils.NewByteIntervalList(),
queuedFrames: make(map[protocol.ByteCount]*wire.StreamFrame),
}
s.gaps.PushFront(utils.ByteInterval{Start: 0, End: protocol.MaxByteCount})
return &s
}
func (s *streamFrameSorter) Push(frame *wire.StreamFrame) error {
if frame.DataLen() == 0 {
if frame.FinBit {
s.queuedFrames[frame.Offset] = frame
return nil
}
return errEmptyStreamData
}
var wasCut bool
if oldFrame, ok := s.queuedFrames[frame.Offset]; ok {
if frame.DataLen() <= oldFrame.DataLen() {
return errDuplicateStreamData
}
frame.Data = frame.Data[oldFrame.DataLen():]
frame.Offset += oldFrame.DataLen()
wasCut = true
}
start := frame.Offset
end := frame.Offset + frame.DataLen()
// skip all gaps that are before this stream frame
var gap *utils.ByteIntervalElement
for gap = s.gaps.Front(); gap != nil; gap = gap.Next() {
// the frame is a duplicate. Ignore it
if end <= gap.Value.Start {
return errDuplicateStreamData
}
if end > gap.Value.Start && start <= gap.Value.End {
break
}
}
if gap == nil {
return errors.New("StreamFrameSorter BUG: no gap found")
}
if start < gap.Value.Start {
add := gap.Value.Start - start
frame.Offset += add
start += add
frame.Data = frame.Data[add:]
wasCut = true
}
// find the highest gaps whose Start lies before the end of the frame
endGap := gap
for end >= endGap.Value.End {
nextEndGap := endGap.Next()
if nextEndGap == nil {
return errors.New("StreamFrameSorter BUG: no end gap found")
}
if endGap != gap {
s.gaps.Remove(endGap)
}
if end <= nextEndGap.Value.Start {
break
}
// delete queued frames completely covered by the current frame
delete(s.queuedFrames, endGap.Value.End)
endGap = nextEndGap
}
if end > endGap.Value.End {
cutLen := end - endGap.Value.End
len := frame.DataLen() - cutLen
end -= cutLen
frame.Data = frame.Data[:len]
wasCut = true
}
if start == gap.Value.Start {
if end >= gap.Value.End {
// the frame completely fills this gap
// delete the gap
s.gaps.Remove(gap)
}
if end < endGap.Value.End {
// the frame covers the beginning of the gap
// adjust the Start value to shrink the gap
endGap.Value.Start = end
}
} else if end == endGap.Value.End {
// the frame covers the end of the gap
// adjust the End value to shrink the gap
gap.Value.End = start
} else {
if gap == endGap {
// the frame lies within the current gap, splitting it into two
// insert a new gap and adjust the current one
intv := utils.ByteInterval{Start: end, End: gap.Value.End}
s.gaps.InsertAfter(intv, gap)
gap.Value.End = start
} else {
gap.Value.End = start
endGap.Value.Start = end
}
}
if s.gaps.Len() > protocol.MaxStreamFrameSorterGaps {
return errTooManyGapsInReceivedStreamData
}
if wasCut {
data := make([]byte, frame.DataLen())
copy(data, frame.Data)
frame.Data = data
}
s.queuedFrames[frame.Offset] = frame
return nil
}
func (s *streamFrameSorter) Pop() *wire.StreamFrame {
frame := s.Head()
if frame != nil {
s.readPosition += frame.DataLen()
delete(s.queuedFrames, frame.Offset)
}
return frame
}
func (s *streamFrameSorter) Head() *wire.StreamFrame {
frame, ok := s.queuedFrames[s.readPosition]
if ok {
return frame
}
return nil
}