github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/framer.go (about) 1 package quic 2 3 import ( 4 "errors" 5 "sync" 6 7 "github.com/metacubex/quic-go/internal/ackhandler" 8 "github.com/metacubex/quic-go/internal/protocol" 9 "github.com/metacubex/quic-go/internal/utils/ringbuffer" 10 "github.com/metacubex/quic-go/internal/wire" 11 "github.com/metacubex/quic-go/quicvarint" 12 ) 13 14 type framer interface { 15 HasData() bool 16 17 QueueControlFrame(wire.Frame) 18 AppendControlFrames([]ackhandler.Frame, protocol.ByteCount, protocol.Version) ([]ackhandler.Frame, protocol.ByteCount) 19 20 AddActiveStream(protocol.StreamID) 21 AppendStreamFrames([]ackhandler.StreamFrame, protocol.ByteCount, protocol.Version) ([]ackhandler.StreamFrame, protocol.ByteCount) 22 23 Handle0RTTRejection() error 24 25 // QueuedTooManyControlFrames says if the control frame queue exceeded its maximum queue length. 26 // This is a hack. 27 // It is easier to implement than propagating an error return value in QueueControlFrame. 28 // The correct solution would be to queue frames with their respective structs. 29 // See https://github.com/metacubex/quic-go/issues/4271 for the queueing of stream-related control frames. 30 QueuedTooManyControlFrames() bool 31 } 32 33 const ( 34 maxPathResponses = 256 35 maxControlFrames = 16 << 10 36 ) 37 38 type framerI struct { 39 mutex sync.Mutex 40 41 streamGetter streamGetter 42 43 activeStreams map[protocol.StreamID]struct{} 44 streamQueue ringbuffer.RingBuffer[protocol.StreamID] 45 46 controlFrameMutex sync.Mutex 47 controlFrames []wire.Frame 48 pathResponses []*wire.PathResponseFrame 49 queuedTooManyControlFrames bool 50 } 51 52 var _ framer = &framerI{} 53 54 func newFramer(streamGetter streamGetter) framer { 55 return &framerI{ 56 streamGetter: streamGetter, 57 activeStreams: make(map[protocol.StreamID]struct{}), 58 } 59 } 60 61 func (f *framerI) HasData() bool { 62 f.mutex.Lock() 63 hasData := !f.streamQueue.Empty() 64 f.mutex.Unlock() 65 if hasData { 66 return true 67 } 68 f.controlFrameMutex.Lock() 69 defer f.controlFrameMutex.Unlock() 70 return len(f.controlFrames) > 0 || len(f.pathResponses) > 0 71 } 72 73 func (f *framerI) QueueControlFrame(frame wire.Frame) { 74 f.controlFrameMutex.Lock() 75 defer f.controlFrameMutex.Unlock() 76 77 if pr, ok := frame.(*wire.PathResponseFrame); ok { 78 // Only queue up to maxPathResponses PATH_RESPONSE frames. 79 // This limit should be high enough to never be hit in practice, 80 // unless the peer is doing something malicious. 81 if len(f.pathResponses) >= maxPathResponses { 82 return 83 } 84 f.pathResponses = append(f.pathResponses, pr) 85 return 86 } 87 // This is a hack. 88 if len(f.controlFrames) >= maxControlFrames { 89 f.queuedTooManyControlFrames = true 90 return 91 } 92 f.controlFrames = append(f.controlFrames, frame) 93 } 94 95 func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.Version) ([]ackhandler.Frame, protocol.ByteCount) { 96 f.controlFrameMutex.Lock() 97 defer f.controlFrameMutex.Unlock() 98 99 var length protocol.ByteCount 100 // add a PATH_RESPONSE first, but only pack a single PATH_RESPONSE per packet 101 if len(f.pathResponses) > 0 { 102 frame := f.pathResponses[0] 103 frameLen := frame.Length(v) 104 if frameLen <= maxLen { 105 frames = append(frames, ackhandler.Frame{Frame: frame}) 106 length += frameLen 107 f.pathResponses = f.pathResponses[1:] 108 } 109 } 110 111 for len(f.controlFrames) > 0 { 112 frame := f.controlFrames[len(f.controlFrames)-1] 113 frameLen := frame.Length(v) 114 if length+frameLen > maxLen { 115 break 116 } 117 frames = append(frames, ackhandler.Frame{Frame: frame}) 118 length += frameLen 119 f.controlFrames = f.controlFrames[:len(f.controlFrames)-1] 120 } 121 return frames, length 122 } 123 124 func (f *framerI) QueuedTooManyControlFrames() bool { 125 return f.queuedTooManyControlFrames 126 } 127 128 func (f *framerI) AddActiveStream(id protocol.StreamID) { 129 f.mutex.Lock() 130 if _, ok := f.activeStreams[id]; !ok { 131 f.streamQueue.PushBack(id) 132 f.activeStreams[id] = struct{}{} 133 } 134 f.mutex.Unlock() 135 } 136 137 func (f *framerI) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen protocol.ByteCount, v protocol.Version) ([]ackhandler.StreamFrame, protocol.ByteCount) { 138 startLen := len(frames) 139 var length protocol.ByteCount 140 f.mutex.Lock() 141 // pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet 142 numActiveStreams := f.streamQueue.Len() 143 for i := 0; i < numActiveStreams; i++ { 144 if protocol.MinStreamFrameSize+length > maxLen { 145 break 146 } 147 id := f.streamQueue.PopFront() 148 // This should never return an error. Better check it anyway. 149 // The stream will only be in the streamQueue, if it enqueued itself there. 150 str, err := f.streamGetter.GetOrOpenSendStream(id) 151 // The stream can be nil if it completed after it said it had data. 152 if str == nil || err != nil { 153 delete(f.activeStreams, id) 154 continue 155 } 156 remainingLen := maxLen - length 157 // For the last STREAM frame, we'll remove the DataLen field later. 158 // Therefore, we can pretend to have more bytes available when popping 159 // the STREAM frame (which will always have the DataLen set). 160 remainingLen += protocol.ByteCount(quicvarint.Len(uint64(remainingLen))) 161 frame, ok, hasMoreData := str.popStreamFrame(remainingLen, v) 162 if hasMoreData { // put the stream back in the queue (at the end) 163 f.streamQueue.PushBack(id) 164 } else { // no more data to send. Stream is not active 165 delete(f.activeStreams, id) 166 } 167 // The frame can be "nil" 168 // * if the receiveStream was canceled after it said it had data 169 // * the remaining size doesn't allow us to add another STREAM frame 170 if !ok { 171 continue 172 } 173 frames = append(frames, frame) 174 length += frame.Frame.Length(v) 175 } 176 f.mutex.Unlock() 177 if len(frames) > startLen { 178 l := frames[len(frames)-1].Frame.Length(v) 179 // account for the smaller size of the last STREAM frame 180 frames[len(frames)-1].Frame.DataLenPresent = false 181 length += frames[len(frames)-1].Frame.Length(v) - l 182 } 183 return frames, length 184 } 185 186 func (f *framerI) Handle0RTTRejection() error { 187 f.mutex.Lock() 188 defer f.mutex.Unlock() 189 190 f.controlFrameMutex.Lock() 191 f.streamQueue.Clear() 192 for id := range f.activeStreams { 193 delete(f.activeStreams, id) 194 } 195 var j int 196 for i, frame := range f.controlFrames { 197 switch frame.(type) { 198 case *wire.MaxDataFrame, *wire.MaxStreamDataFrame, *wire.MaxStreamsFrame: 199 return errors.New("didn't expect MAX_DATA / MAX_STREAM_DATA / MAX_STREAMS frame to be sent in 0-RTT") 200 case *wire.DataBlockedFrame, *wire.StreamDataBlockedFrame, *wire.StreamsBlockedFrame: 201 continue 202 default: 203 f.controlFrames[j] = f.controlFrames[i] 204 j++ 205 } 206 } 207 f.controlFrames = f.controlFrames[:j] 208 f.controlFrameMutex.Unlock() 209 return nil 210 }