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