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