github.com/MerlinKodo/quic-go@v0.39.2/framer.go (about) 1 package quic 2 3 import ( 4 "errors" 5 "sync" 6 7 "github.com/MerlinKodo/quic-go/internal/ackhandler" 8 "github.com/MerlinKodo/quic-go/internal/protocol" 9 "github.com/MerlinKodo/quic-go/internal/utils/ringbuffer" 10 "github.com/MerlinKodo/quic-go/internal/wire" 11 "github.com/MerlinKodo/quic-go/quicvarint" 12 ) 13 14 type framer interface { 15 HasData() bool 16 17 QueueControlFrame(wire.Frame) 18 AppendControlFrames([]ackhandler.Frame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount) 19 20 AddActiveStream(protocol.StreamID) 21 AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount) 22 23 Handle0RTTRejection() error 24 } 25 26 type framerI struct { 27 mutex sync.Mutex 28 29 streamGetter streamGetter 30 31 activeStreams map[protocol.StreamID]struct{} 32 streamQueue ringbuffer.RingBuffer[protocol.StreamID] 33 34 controlFrameMutex sync.Mutex 35 controlFrames []wire.Frame 36 } 37 38 var _ framer = &framerI{} 39 40 func newFramer(streamGetter streamGetter) framer { 41 return &framerI{ 42 streamGetter: streamGetter, 43 activeStreams: make(map[protocol.StreamID]struct{}), 44 } 45 } 46 47 func (f *framerI) HasData() bool { 48 f.mutex.Lock() 49 hasData := !f.streamQueue.Empty() 50 f.mutex.Unlock() 51 if hasData { 52 return true 53 } 54 f.controlFrameMutex.Lock() 55 hasData = len(f.controlFrames) > 0 56 f.controlFrameMutex.Unlock() 57 return hasData 58 } 59 60 func (f *framerI) QueueControlFrame(frame wire.Frame) { 61 f.controlFrameMutex.Lock() 62 f.controlFrames = append(f.controlFrames, frame) 63 f.controlFrameMutex.Unlock() 64 } 65 66 func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.Frame, protocol.ByteCount) { 67 var length protocol.ByteCount 68 f.controlFrameMutex.Lock() 69 for len(f.controlFrames) > 0 { 70 frame := f.controlFrames[len(f.controlFrames)-1] 71 frameLen := frame.Length(v) 72 if length+frameLen > maxLen { 73 break 74 } 75 frames = append(frames, ackhandler.Frame{Frame: frame}) 76 length += frameLen 77 f.controlFrames = f.controlFrames[:len(f.controlFrames)-1] 78 } 79 f.controlFrameMutex.Unlock() 80 return frames, length 81 } 82 83 func (f *framerI) AddActiveStream(id protocol.StreamID) { 84 f.mutex.Lock() 85 if _, ok := f.activeStreams[id]; !ok { 86 f.streamQueue.PushBack(id) 87 f.activeStreams[id] = struct{}{} 88 } 89 f.mutex.Unlock() 90 } 91 92 func (f *framerI) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen protocol.ByteCount, v protocol.VersionNumber) ([]ackhandler.StreamFrame, protocol.ByteCount) { 93 startLen := len(frames) 94 var length protocol.ByteCount 95 f.mutex.Lock() 96 // pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet 97 numActiveStreams := f.streamQueue.Len() 98 for i := 0; i < numActiveStreams; i++ { 99 if protocol.MinStreamFrameSize+length > maxLen { 100 break 101 } 102 id := f.streamQueue.PopFront() 103 // This should never return an error. Better check it anyway. 104 // The stream will only be in the streamQueue, if it enqueued itself there. 105 str, err := f.streamGetter.GetOrOpenSendStream(id) 106 // The stream can be nil if it completed after it said it had data. 107 if str == nil || err != nil { 108 delete(f.activeStreams, id) 109 continue 110 } 111 remainingLen := maxLen - length 112 // For the last STREAM frame, we'll remove the DataLen field later. 113 // Therefore, we can pretend to have more bytes available when popping 114 // the STREAM frame (which will always have the DataLen set). 115 remainingLen += quicvarint.Len(uint64(remainingLen)) 116 frame, ok, hasMoreData := str.popStreamFrame(remainingLen, v) 117 if hasMoreData { // put the stream back in the queue (at the end) 118 f.streamQueue.PushBack(id) 119 } else { // no more data to send. Stream is not active 120 delete(f.activeStreams, id) 121 } 122 // The frame can be "nil" 123 // * if the receiveStream was canceled after it said it had data 124 // * the remaining size doesn't allow us to add another STREAM frame 125 if !ok { 126 continue 127 } 128 frames = append(frames, frame) 129 length += frame.Frame.Length(v) 130 } 131 f.mutex.Unlock() 132 if len(frames) > startLen { 133 l := frames[len(frames)-1].Frame.Length(v) 134 // account for the smaller size of the last STREAM frame 135 frames[len(frames)-1].Frame.DataLenPresent = false 136 length += frames[len(frames)-1].Frame.Length(v) - l 137 } 138 return frames, length 139 } 140 141 func (f *framerI) Handle0RTTRejection() error { 142 f.mutex.Lock() 143 defer f.mutex.Unlock() 144 145 f.controlFrameMutex.Lock() 146 f.streamQueue.Clear() 147 for id := range f.activeStreams { 148 delete(f.activeStreams, id) 149 } 150 var j int 151 for i, frame := range f.controlFrames { 152 switch frame.(type) { 153 case *wire.MaxDataFrame, *wire.MaxStreamDataFrame, *wire.MaxStreamsFrame: 154 return errors.New("didn't expect MAX_DATA / MAX_STREAM_DATA / MAX_STREAMS frame to be sent in 0-RTT") 155 case *wire.DataBlockedFrame, *wire.StreamDataBlockedFrame, *wire.StreamsBlockedFrame: 156 continue 157 default: 158 f.controlFrames[j] = f.controlFrames[i] 159 j++ 160 } 161 } 162 f.controlFrames = f.controlFrames[:j] 163 f.controlFrameMutex.Unlock() 164 return nil 165 }