github.com/Psiphon-Labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/quic/gquic-go/framer.go (about)

     1  package gquic
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go/internal/protocol"
     7  	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic/gquic-go/internal/wire"
     8  )
     9  
    10  type framer struct {
    11  	streamGetter streamGetter
    12  	cryptoStream cryptoStream
    13  	version      protocol.VersionNumber
    14  
    15  	streamQueueMutex sync.Mutex
    16  	activeStreams    map[protocol.StreamID]struct{}
    17  	streamQueue      []protocol.StreamID
    18  
    19  	controlFrameMutex sync.Mutex
    20  	controlFrames     []wire.Frame
    21  }
    22  
    23  func newFramer(
    24  	cryptoStream cryptoStream,
    25  	streamGetter streamGetter,
    26  	v protocol.VersionNumber,
    27  ) *framer {
    28  	return &framer{
    29  		streamGetter:  streamGetter,
    30  		cryptoStream:  cryptoStream,
    31  		activeStreams: make(map[protocol.StreamID]struct{}),
    32  		version:       v,
    33  	}
    34  }
    35  
    36  func (f *framer) QueueControlFrame(frame wire.Frame) {
    37  	f.controlFrameMutex.Lock()
    38  	f.controlFrames = append(f.controlFrames, frame)
    39  	f.controlFrameMutex.Unlock()
    40  }
    41  
    42  func (f *framer) AppendControlFrames(frames []wire.Frame, maxLen protocol.ByteCount) ([]wire.Frame, protocol.ByteCount) {
    43  	var length protocol.ByteCount
    44  	f.controlFrameMutex.Lock()
    45  	for len(f.controlFrames) > 0 {
    46  		frame := f.controlFrames[len(f.controlFrames)-1]
    47  		frameLen := frame.Length(f.version)
    48  		if length+frameLen > maxLen {
    49  			break
    50  		}
    51  		frames = append(frames, frame)
    52  		length += frameLen
    53  		f.controlFrames = f.controlFrames[:len(f.controlFrames)-1]
    54  	}
    55  	f.controlFrameMutex.Unlock()
    56  	return frames, length
    57  }
    58  
    59  // AddActiveStream adds a stream that has data to write.
    60  // It should not be used for the crypto stream.
    61  func (f *framer) AddActiveStream(id protocol.StreamID) {
    62  	f.streamQueueMutex.Lock()
    63  	if _, ok := f.activeStreams[id]; !ok {
    64  		f.streamQueue = append(f.streamQueue, id)
    65  		f.activeStreams[id] = struct{}{}
    66  	}
    67  	f.streamQueueMutex.Unlock()
    68  }
    69  
    70  func (f *framer) AppendStreamFrames(frames []wire.Frame, maxLen protocol.ByteCount) []wire.Frame {
    71  	var length protocol.ByteCount
    72  	f.streamQueueMutex.Lock()
    73  	// pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet
    74  	numActiveStreams := len(f.streamQueue)
    75  	for i := 0; i < numActiveStreams; i++ {
    76  		if maxLen-length < protocol.MinStreamFrameSize {
    77  			break
    78  		}
    79  		id := f.streamQueue[0]
    80  		f.streamQueue = f.streamQueue[1:]
    81  		// This should never return an error. Better check it anyway.
    82  		// The stream will only be in the streamQueue, if it enqueued itself there.
    83  		str, err := f.streamGetter.GetOrOpenSendStream(id)
    84  		// The stream can be nil if it completed after it said it had data.
    85  		if str == nil || err != nil {
    86  			delete(f.activeStreams, id)
    87  			continue
    88  		}
    89  		frame, hasMoreData := str.popStreamFrame(maxLen - length)
    90  		if hasMoreData { // put the stream back in the queue (at the end)
    91  			f.streamQueue = append(f.streamQueue, id)
    92  		} else { // no more data to send. Stream is not active any more
    93  			delete(f.activeStreams, id)
    94  		}
    95  		if frame == nil { // can happen if the receiveStream was canceled after it said it had data
    96  			continue
    97  		}
    98  		frames = append(frames, frame)
    99  		length += frame.Length(f.version)
   100  	}
   101  	f.streamQueueMutex.Unlock()
   102  	return frames
   103  }