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  }