github.com/TugasAkhir-QUIC/quic-go@v0.0.2-0.20240215011318-d20e25a9054c/framer.go (about) 1 package quic 2 3 import ( 4 "errors" 5 "sort" 6 "sync" 7 8 "github.com/TugasAkhir-QUIC/quic-go/internal/ackhandler" 9 "github.com/TugasAkhir-QUIC/quic-go/internal/protocol" 10 "github.com/TugasAkhir-QUIC/quic-go/internal/wire" 11 "github.com/TugasAkhir-QUIC/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 26 const maxPathResponses = 256 27 28 type framerI struct { 29 mutex sync.Mutex 30 31 streamGetter streamGetter 32 33 activeStreams map[protocol.StreamID]struct{} 34 //streamQueue ringbuffer.RingBuffer[protocol.StreamID] 35 streamQueue []protocol.StreamID 36 37 controlFrameMutex sync.Mutex 38 controlFrames []wire.Frame 39 pathResponses []*wire.PathResponseFrame 40 } 41 42 var _ framer = &framerI{} 43 44 func newFramer(streamGetter streamGetter) framer { 45 return &framerI{ 46 streamGetter: streamGetter, 47 activeStreams: make(map[protocol.StreamID]struct{}), 48 } 49 } 50 51 func (f *framerI) HasData() bool { 52 f.mutex.Lock() 53 hasData := len(f.streamQueue) > 0 54 f.mutex.Unlock() 55 if hasData { 56 return true 57 } 58 f.controlFrameMutex.Lock() 59 defer f.controlFrameMutex.Unlock() 60 return len(f.controlFrames) > 0 || len(f.pathResponses) > 0 61 } 62 63 func (f *framerI) QueueControlFrame(frame wire.Frame) { 64 f.controlFrameMutex.Lock() 65 defer f.controlFrameMutex.Unlock() 66 67 if pr, ok := frame.(*wire.PathResponseFrame); ok { 68 // Only queue up to maxPathResponses PATH_RESPONSE frames. 69 // This limit should be high enough to never be hit in practice, 70 // unless the peer is doing something malicious. 71 if len(f.pathResponses) >= maxPathResponses { 72 return 73 } 74 f.pathResponses = append(f.pathResponses, pr) 75 return 76 } 77 f.controlFrames = append(f.controlFrames, frame) 78 } 79 80 func (f *framerI) AppendControlFrames(frames []ackhandler.Frame, maxLen protocol.ByteCount, v protocol.Version) ([]ackhandler.Frame, protocol.ByteCount) { 81 f.controlFrameMutex.Lock() 82 defer f.controlFrameMutex.Unlock() 83 84 var length protocol.ByteCount 85 // add a PATH_RESPONSE first, but only pack a single PATH_RESPONSE per packet 86 if len(f.pathResponses) > 0 { 87 frame := f.pathResponses[0] 88 frameLen := frame.Length(v) 89 if frameLen <= maxLen { 90 frames = append(frames, ackhandler.Frame{Frame: frame}) 91 length += frameLen 92 f.pathResponses = f.pathResponses[1:] 93 } 94 } 95 96 for len(f.controlFrames) > 0 { 97 frame := f.controlFrames[len(f.controlFrames)-1] 98 frameLen := frame.Length(v) 99 if length+frameLen > maxLen { 100 break 101 } 102 frames = append(frames, ackhandler.Frame{Frame: frame}) 103 length += frameLen 104 f.controlFrames = f.controlFrames[:len(f.controlFrames)-1] 105 } 106 return frames, length 107 } 108 109 func (f *framerI) AddActiveStream(id protocol.StreamID) { 110 f.mutex.Lock() 111 if _, ok := f.activeStreams[id]; !ok { 112 f.streamQueue = append(f.streamQueue, id) 113 f.activeStreams[id] = struct{}{} 114 f.sortQueue() 115 } 116 f.mutex.Unlock() 117 } 118 119 func (f *framerI) sortQueue() { 120 // Sort the queue by descending priority order 121 sort.SliceStable(f.streamQueue, func(i int, j int) bool { 122 str1, err := f.streamGetter.GetOrOpenSendStream(f.streamQueue[i]) 123 if str1 == nil || err != nil { 124 return false // Push to the front so we can pop it 125 } 126 127 str2, err := f.streamGetter.GetOrOpenSendStream(f.streamQueue[j]) 128 if str2 == nil || err != nil { 129 return true // Push to the front so we can pop it 130 } 131 132 return str1.getPriority() > str2.getPriority() 133 }) 134 } 135 136 func (f *framerI) AppendStreamFrames(frames []ackhandler.StreamFrame, maxLen protocol.ByteCount, v protocol.Version) ([]ackhandler.StreamFrame, protocol.ByteCount) { 137 startLen := len(frames) 138 var length protocol.ByteCount 139 f.mutex.Lock() 140 141 // TODO perform this sort when SetPriority() is called 142 f.sortQueue() 143 144 // Record information about streams with the same priority 145 priorityCurrent := 0 // The current priority value 146 prioritySent := 0 // The number of sent streams with this priority 147 priorityUnsent := 0 // The number of unsent streams with this priority 148 149 i := 0 150 151 // pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet 152 for i < len(f.streamQueue) { 153 id := f.streamQueue[i] 154 // This should never return an error. Better check it anyway. 155 // The stream will only be in the streamQueue, if it enqueued itself there. 156 str, err := f.streamGetter.GetOrOpenSendStream(id) 157 // The stream can be nil if it completed after it said it had data. 158 if str == nil || err != nil { 159 delete(f.activeStreams, id) 160 161 // Shift the remaining elements in the queue forward 162 copy(f.streamQueue[i:], f.streamQueue[i+1:]) 163 f.streamQueue = f.streamQueue[:len(f.streamQueue)-1] 164 165 // Don't increment i since we just removed an element 166 continue 167 } 168 169 // Get the priority for the current stream 170 priority := str.getPriority() 171 full := protocol.MinStreamFrameSize+length > maxLen 172 if full { 173 // If we're full, see if the previous streams had the same priority 174 if priority != priorityCurrent { 175 // We can stop interating since we've found all streams with the same priority 176 break 177 } 178 179 // Keep looping until this is no longer the case. 180 priorityUnsent += 1 181 i += 1 182 183 continue 184 } 185 186 // See if the previous streams had the same priority 187 if i == 0 || priority != priorityCurrent { 188 // We just sent a new priority level; reset our counters 189 priorityCurrent = priority 190 priorityUnsent = 0 191 prioritySent = 0 192 } 193 194 remainingLen := maxLen - length 195 // For the last STREAM frame, we'll remove the DataLen field later. 196 // Therefore, we can pretend to have more bytes available when popping 197 // the STREAM frame (which will always have the DataLen set). 198 remainingLen += quicvarint.Len(uint64(remainingLen)) 199 200 frame, ok, hasMoreData := str.popStreamFrame(remainingLen, v) 201 // The frame can be "nil" 202 // * if the receiveStream was canceled after it said it had data 203 // * the remaining size doesn't allow us to add another STREAM frame 204 if ok { 205 frames = append(frames, frame) 206 length += frame.Frame.Length(v) 207 } 208 if !hasMoreData { 209 // no more data to send. Stream is not active any more 210 delete(f.activeStreams, id) 211 212 // Shift the remaining elements in the queue forward 213 copy(f.streamQueue[i:], f.streamQueue[i+1:]) 214 f.streamQueue = f.streamQueue[:len(f.streamQueue)-1] 215 216 // Don't increment i since we just removed an element 217 continue 218 } 219 220 i += 1 221 prioritySent += 1 222 } 223 224 if priorityUnsent > 0 && prioritySent > 0 { 225 // There were some streams sent and some streams unsent within the same priority. 226 // We want to swap the last `priorityUnsent` values with the prior `prioritySent` values. 227 // This way we will round-robin streams with the same priority. 228 swap := make([]protocol.StreamID, prioritySent) 229 230 end := i 231 middle := end - priorityUnsent 232 start := middle - prioritySent 233 234 copy(swap, f.streamQueue[start:middle+1]) 235 copy(f.streamQueue[start:], f.streamQueue[middle:end]) 236 copy(f.streamQueue[end-len(swap):], swap) 237 238 // Example: 239 // i = 7 240 // streamQueue (priority): [ 7, 7, 5, 5, 5, 5, 5, 2, 2 ] 241 // priorityUnset = 3 242 // prioritySent = 2 243 244 // We want to move index 2,3 to index 5,6 and index 4,5,6 to index 2,3,4 245 // end = 7 246 // middle = 4 247 // start = 2 248 249 // copy(swap, queue[2:5]) 250 // copy(queue[2:], queue[4:7]) 251 // copy(queue[5:], swap) 252 } 253 254 f.mutex.Unlock() 255 if len(frames) > startLen { 256 l := frames[len(frames)-1].Frame.Length(v) 257 // account for the smaller size of the last STREAM frame 258 frames[len(frames)-1].Frame.DataLenPresent = false 259 length += frames[len(frames)-1].Frame.Length(v) - l 260 } 261 262 return frames, length 263 } 264 265 func (f *framerI) Handle0RTTRejection() error { 266 f.mutex.Lock() 267 defer f.mutex.Unlock() 268 269 f.controlFrameMutex.Lock() 270 f.streamQueue = f.streamQueue[:0] 271 for id := range f.activeStreams { 272 delete(f.activeStreams, id) 273 } 274 var j int 275 for i, frame := range f.controlFrames { 276 switch frame.(type) { 277 case *wire.MaxDataFrame, *wire.MaxStreamDataFrame, *wire.MaxStreamsFrame: 278 return errors.New("didn't expect MAX_DATA / MAX_STREAM_DATA / MAX_STREAMS frame to be sent in 0-RTT") 279 case *wire.DataBlockedFrame, *wire.StreamDataBlockedFrame, *wire.StreamsBlockedFrame: 280 continue 281 default: 282 f.controlFrames[j] = f.controlFrames[i] 283 j++ 284 } 285 } 286 f.controlFrames = f.controlFrames[:j] 287 f.controlFrameMutex.Unlock() 288 return nil 289 }