github.com/tumi8/quic-go@v0.37.4-tum/framer.go (about)

     1  package quic
     2  
     3  import (
     4  	"errors"
     5  	"sync"
     6  
     7  	"github.com/tumi8/quic-go/noninternal/ackhandler"
     8  	"github.com/tumi8/quic-go/noninternal/protocol"
     9  	"github.com/tumi8/quic-go/noninternal/utils/ringbuffer"
    10  	"github.com/tumi8/quic-go/noninternal/wire"
    11  	"github.com/tumi8/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  }