github.com/danielpfeifer02/quic-go-prio-packs@v0.41.0-28/crypto_stream.go (about)

     1  package quic
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/protocol"
     8  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/qerr"
     9  	"github.com/danielpfeifer02/quic-go-prio-packs/internal/wire"
    10  )
    11  
    12  type cryptoStream interface {
    13  	// for receiving data
    14  	HandleCryptoFrame(*wire.CryptoFrame) error
    15  	GetCryptoData() []byte
    16  	Finish() error
    17  	// for sending data
    18  	io.Writer
    19  	HasData() bool
    20  	PopCryptoFrame(protocol.ByteCount) *wire.CryptoFrame
    21  }
    22  
    23  type cryptoStreamImpl struct {
    24  	queue  *frameSorter
    25  	msgBuf []byte
    26  
    27  	highestOffset protocol.ByteCount
    28  	finished      bool
    29  
    30  	writeOffset protocol.ByteCount
    31  	writeBuf    []byte
    32  }
    33  
    34  func newCryptoStream() cryptoStream {
    35  	return &cryptoStreamImpl{queue: newFrameSorter()}
    36  }
    37  
    38  func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
    39  	highestOffset := f.Offset + protocol.ByteCount(len(f.Data))
    40  	if maxOffset := highestOffset; maxOffset > protocol.MaxCryptoStreamOffset {
    41  		return &qerr.TransportError{
    42  			ErrorCode:    qerr.CryptoBufferExceeded,
    43  			ErrorMessage: fmt.Sprintf("received invalid offset %d on crypto stream, maximum allowed %d", maxOffset, protocol.MaxCryptoStreamOffset),
    44  		}
    45  	}
    46  	if s.finished {
    47  		if highestOffset > s.highestOffset {
    48  			// reject crypto data received after this stream was already finished
    49  			return &qerr.TransportError{
    50  				ErrorCode:    qerr.ProtocolViolation,
    51  				ErrorMessage: "received crypto data after change of encryption level",
    52  			}
    53  		}
    54  		// ignore data with a smaller offset than the highest received
    55  		// could e.g. be a retransmission
    56  		return nil
    57  	}
    58  	s.highestOffset = max(s.highestOffset, highestOffset)
    59  	if err := s.queue.Push(f.Data, f.Offset, nil); err != nil {
    60  		return err
    61  	}
    62  	for {
    63  		_, data, _ := s.queue.Pop()
    64  		if data == nil {
    65  			return nil
    66  		}
    67  		s.msgBuf = append(s.msgBuf, data...)
    68  	}
    69  }
    70  
    71  // GetCryptoData retrieves data that was received in CRYPTO frames
    72  func (s *cryptoStreamImpl) GetCryptoData() []byte {
    73  	b := s.msgBuf
    74  	s.msgBuf = nil
    75  	return b
    76  }
    77  
    78  func (s *cryptoStreamImpl) Finish() error {
    79  	if s.queue.HasMoreData() {
    80  		return &qerr.TransportError{
    81  			ErrorCode:    qerr.ProtocolViolation,
    82  			ErrorMessage: "encryption level changed, but crypto stream has more data to read",
    83  		}
    84  	}
    85  	s.finished = true
    86  	return nil
    87  }
    88  
    89  // Writes writes data that should be sent out in CRYPTO frames
    90  func (s *cryptoStreamImpl) Write(p []byte) (int, error) {
    91  	s.writeBuf = append(s.writeBuf, p...)
    92  	return len(p), nil
    93  }
    94  
    95  func (s *cryptoStreamImpl) HasData() bool {
    96  	return len(s.writeBuf) > 0
    97  }
    98  
    99  func (s *cryptoStreamImpl) PopCryptoFrame(maxLen protocol.ByteCount) *wire.CryptoFrame {
   100  	f := &wire.CryptoFrame{Offset: s.writeOffset}
   101  	n := min(f.MaxDataLen(maxLen), protocol.ByteCount(len(s.writeBuf)))
   102  	f.Data = s.writeBuf[:n]
   103  	s.writeBuf = s.writeBuf[n:]
   104  	s.writeOffset += n
   105  	return f
   106  }