forked from quic-go/quic-go
implement the crypto stream for post-handshake crypto messages
This commit is contained in:
@@ -21,6 +21,35 @@ type cryptoStream interface {
|
|||||||
PopCryptoFrame(protocol.ByteCount) *wire.CryptoFrame
|
PopCryptoFrame(protocol.ByteCount) *wire.CryptoFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type postHandshakeCryptoStream struct {
|
||||||
|
cryptoStream
|
||||||
|
|
||||||
|
framer framer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPostHandshakeCryptoStream(framer framer) cryptoStream {
|
||||||
|
return &postHandshakeCryptoStream{
|
||||||
|
cryptoStream: newCryptoStream(),
|
||||||
|
framer: framer,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes post-handshake messages.
|
||||||
|
// For simplicity, post-handshake crypto messages are treated as control frames.
|
||||||
|
// The framer functions as a stack (LIFO), so if there are multiple writes,
|
||||||
|
// they will be returned in the opposite order.
|
||||||
|
// This is acceptable, since post-handshake crypto messages are very rare.
|
||||||
|
func (s *postHandshakeCryptoStream) Write(p []byte) (int, error) {
|
||||||
|
n, err := s.cryptoStream.Write(p)
|
||||||
|
if err != nil {
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
for s.cryptoStream.HasData() {
|
||||||
|
s.framer.QueueControlFrame(s.PopCryptoFrame(protocol.MaxPostHandshakeCryptoFrameSize))
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
type cryptoStreamImpl struct {
|
type cryptoStreamImpl struct {
|
||||||
queue *frameSorter
|
queue *frameSorter
|
||||||
msgBuf []byte
|
msgBuf []byte
|
||||||
@@ -33,9 +62,7 @@ type cryptoStreamImpl struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newCryptoStream() cryptoStream {
|
func newCryptoStream() cryptoStream {
|
||||||
return &cryptoStreamImpl{
|
return &cryptoStreamImpl{queue: newFrameSorter()}
|
||||||
queue: newFrameSorter(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
|
func (s *cryptoStreamImpl) HandleCryptoFrame(f *wire.CryptoFrame) error {
|
||||||
|
|||||||
@@ -180,3 +180,45 @@ var _ = Describe("Crypto Stream", func() {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var _ = Describe("Post Handshake Crypto Stream", func() {
|
||||||
|
var (
|
||||||
|
cs cryptoStream
|
||||||
|
framer framer
|
||||||
|
)
|
||||||
|
|
||||||
|
BeforeEach(func() {
|
||||||
|
framer = newFramer(NewMockStreamGetter(mockCtrl), protocol.VersionTLS)
|
||||||
|
cs = newPostHandshakeCryptoStream(framer)
|
||||||
|
})
|
||||||
|
|
||||||
|
It("queues CRYPTO frames when writing data", func() {
|
||||||
|
n, err := cs.Write([]byte("foo"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(n).To(Equal(3))
|
||||||
|
n, err = cs.Write([]byte("bar"))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(n).To(Equal(3))
|
||||||
|
frames, _ := framer.AppendControlFrames(nil, 1000)
|
||||||
|
Expect(frames).To(HaveLen(2))
|
||||||
|
Expect(frames).To(ContainElement(&wire.CryptoFrame{Data: []byte("foo")}))
|
||||||
|
Expect(frames).To(ContainElement(&wire.CryptoFrame{Data: []byte("bar"), Offset: 3}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("splits large writes into multiple frames", func() {
|
||||||
|
size := 10 * protocol.MaxPostHandshakeCryptoFrameSize
|
||||||
|
n, err := cs.Write(make([]byte, size))
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(n).To(BeEquivalentTo(size))
|
||||||
|
frames, _ := framer.AppendControlFrames(nil, protocol.MaxByteCount)
|
||||||
|
Expect(frames).To(HaveLen(11)) // one more for framing overhead
|
||||||
|
var dataLen int
|
||||||
|
for _, f := range frames {
|
||||||
|
Expect(f.Length(protocol.VersionTLS)).To(BeNumerically("<=", protocol.MaxPostHandshakeCryptoFrameSize))
|
||||||
|
Expect(f).To(BeAssignableToTypeOf(&wire.CryptoFrame{}))
|
||||||
|
dataLen += len(f.(*wire.CryptoFrame).Data)
|
||||||
|
}
|
||||||
|
Expect(dataLen).To(BeEquivalentTo(size))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|||||||
@@ -103,6 +103,10 @@ const RetiredConnectionIDDeleteTimeout = 5 * time.Second
|
|||||||
// 2. it reduces the head-of-line blocking, when a packet is lost
|
// 2. it reduces the head-of-line blocking, when a packet is lost
|
||||||
const MinStreamFrameSize ByteCount = 128
|
const MinStreamFrameSize ByteCount = 128
|
||||||
|
|
||||||
|
// MaxPostHandshakeCryptoFrameSize is the maximum size of CRYPTO frames
|
||||||
|
// we send after the handshake completes.
|
||||||
|
const MaxPostHandshakeCryptoFrameSize ByteCount = 1000
|
||||||
|
|
||||||
// MaxAckFrameSize is the maximum size for an ACK frame that we write
|
// MaxAckFrameSize is the maximum size for an ACK frame that we write
|
||||||
// Due to the varint encoding, ACK frames can grow (almost) indefinitely large.
|
// Due to the varint encoding, ACK frames can grow (almost) indefinitely large.
|
||||||
// The MaxAckFrameSize should be large enough to encode many ACK range,
|
// The MaxAckFrameSize should be large enough to encode many ACK range,
|
||||||
|
|||||||
Reference in New Issue
Block a user