implement ReadMultiBuffer in quic conn

This commit is contained in:
Darien Raymond 2018-11-30 14:41:11 +01:00
parent d649de172e
commit 61ad81c326
No known key found for this signature in database
GPG Key ID: 7251FFA14BB18169
8 changed files with 80 additions and 77 deletions

View File

@ -142,6 +142,29 @@ func (c *interConn) Read(b []byte) (int, error) {
return c.stream.Read(b)
}
func (c *interConn) ReadMultiBuffer() (buf.MultiBuffer, error) {
mb := make(buf.MultiBuffer, 0, 8)
{
b := buf.New()
if _, err := b.ReadFrom(c.stream); err != nil {
b.Release()
return nil, err
}
mb = append(mb, b)
}
for c.stream.HasMoreData() {
b := buf.New()
if _, err := b.ReadFrom(c.stream); err != nil {
b.Release()
break
}
mb = append(mb, b)
}
return mb, nil
}
func (c *interConn) WriteMultiBuffer(mb buf.MultiBuffer) error {
if mb.IsEmpty() {
return nil

View File

@ -8,13 +8,6 @@ const MaxPacketSizeIPv4 = 1252
// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
const MaxPacketSizeIPv6 = 1232
// MinStatelessResetSize is the minimum size of a stateless reset packet
const MinStatelessResetSize = 1 + 20 + 16
// NonForwardSecurePacketSizeReduction is the number of bytes a non forward-secure packet has to be smaller than a forward-secure packet
// This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames
const NonForwardSecurePacketSizeReduction = 50
const defaultMaxCongestionWindowPackets = 1000
// DefaultMaxCongestionWindow is the default for the max congestion window
@ -23,8 +16,7 @@ const DefaultMaxCongestionWindow ByteCount = defaultMaxCongestionWindowPackets *
// InitialCongestionWindow is the initial congestion window in QUIC packets
const InitialCongestionWindow ByteCount = 32 * DefaultTCPMSS
// MaxUndecryptablePackets limits the number of undecryptable packets that a
// session queues for later until it sends a public reset.
// MaxUndecryptablePackets limits the number of undecryptable packets that are queued in the session.
const MaxUndecryptablePackets = 10
// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window

View File

@ -58,5 +58,8 @@ const DefaultTCPMSS ByteCount = 1460
// MinInitialPacketSize is the minimum size an Initial packet is required to have.
const MinInitialPacketSize = 1200
// MinStatelessResetSize is the minimum size of a stateless reset packet
const MinStatelessResetSize = 1 /* first byte */ + 22 /* random bytes */ + 16 /* token */
// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
const MinConnectionIDLenInitial = 8

View File

@ -96,7 +96,6 @@ type packetPacker struct {
acks ackFrameSource
maxPacketSize protocol.ByteCount
hasSentPacket bool // has the packetPacker already sent a packet
numNonRetransmittableAcks int
}
@ -168,14 +167,12 @@ func (p *packetPacker) MaybePackAckPacket() (*packedPacket, error) {
// For packets sent after completion of the handshake, it might happen that 2 packets have to be sent.
// This can happen e.g. when a longer packet number is used in the header.
func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedPacket, error) {
if packet.EncryptionLevel != protocol.Encryption1RTT {
p, err := p.packHandshakeRetransmission(packet)
return []*packedPacket{p}, err
}
var controlFrames []wire.Frame
var streamFrames []*wire.StreamFrame
for _, f := range packet.Frames {
// CRYPTO frames are treated as control frames here.
// Since we're making sure that the header can never be larger for a retransmission,
// we never have to split CRYPTO frames.
if sf, ok := f.(*wire.StreamFrame); ok {
sf.DataLenPresent = true
streamFrames = append(streamFrames, sf)
@ -244,27 +241,6 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP
return packets, nil
}
// packHandshakeRetransmission retransmits a handshake packet
func (p *packetPacker) packHandshakeRetransmission(packet *ackhandler.Packet) (*packedPacket, error) {
sealer, err := p.cryptoSetup.GetSealerWithEncryptionLevel(packet.EncryptionLevel)
if err != nil {
return nil, err
}
// make sure that the retransmission for an Initial packet is sent as an Initial packet
if packet.PacketType == protocol.PacketTypeInitial {
p.hasSentPacket = false
}
header := p.getHeader(packet.EncryptionLevel)
header.Type = packet.PacketType
raw, err := p.writeAndSealPacket(header, packet.Frames, sealer)
return &packedPacket{
header: header,
raw: raw,
frames: packet.Frames,
encryptionLevel: packet.EncryptionLevel,
}, err
}
// PackPacket packs a new packet
// the other controlFrames are sent in the next packet, but might be queued and sent in the next packet if the packet would overflow MaxPacketSize otherwise
func (p *packetPacker) PackPacket() (*packedPacket, error) {
@ -275,10 +251,6 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
if packet != nil {
return packet, nil
}
// if this is the first packet to be send, make sure it contains stream data
if !p.hasSentPacket && packet == nil {
return nil, nil
}
encLevel, sealer := p.cryptoSetup.GetSealer()
header := p.getHeader(encLevel)
@ -288,7 +260,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
}
maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLen
frames, err := p.composeNextPacket(maxSize, p.canSendData(encLevel))
frames, err := p.composeNextPacket(maxSize)
if err != nil {
return nil, err
}
@ -360,10 +332,7 @@ func (p *packetPacker) maybePackCryptoPacket() (*packedPacket, error) {
}, nil
}
func (p *packetPacker) composeNextPacket(
maxFrameSize protocol.ByteCount,
canSendStreamFrames bool,
) ([]wire.Frame, error) {
func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount) ([]wire.Frame, error) {
var length protocol.ByteCount
var frames []wire.Frame
@ -377,10 +346,6 @@ func (p *packetPacker) composeNextPacket(
frames, lengthAdded = p.framer.AppendControlFrames(frames, maxFrameSize-length)
length += lengthAdded
if !canSendStreamFrames {
return frames, nil
}
// temporarily increase the maxFrameSize by the (minimum) length of the DataLen field
// this leads to a properly sized packet in all cases, since we do all the packet length calculations with STREAM frames that have the DataLen set
// however, for the last STREAM frame in the packet, we can omit the DataLen, thus yielding a packet of exactly the correct size
@ -407,6 +372,10 @@ func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Extend
if encLevel != protocol.Encryption1RTT {
header.IsLongHeader = true
// Always send Initial and Handshake packets with the maximum packet number length.
// This simplifies retransmissions: Since the header can't get any larger,
// we don't need to split CRYPTO frames.
header.PacketNumberLen = protocol.PacketNumberLen4
header.SrcConnectionID = p.srcConnID
// Set the length to the maximum packet size.
// Since it is encoded as a varint, this guarantees us that the header will end up at most as big as GetLength() returns.
@ -423,23 +392,24 @@ func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Extend
}
func (p *packetPacker) writeAndSealPacket(
header *wire.ExtendedHeader, frames []wire.Frame,
header *wire.ExtendedHeader,
frames []wire.Frame,
sealer handshake.Sealer,
) ([]byte, error) {
raw := *getPacketBuffer()
buffer := bytes.NewBuffer(raw[:0])
addPadding := p.perspective == protocol.PerspectiveClient && header.Type == protocol.PacketTypeInitial && !p.hasSentPacket
addPaddingForInitial := p.perspective == protocol.PerspectiveClient && header.Type == protocol.PacketTypeInitial
// the length is only needed for Long Headers
if header.IsLongHeader {
if p.perspective == protocol.PerspectiveClient && header.Type == protocol.PacketTypeInitial {
header.Token = p.token
}
if addPadding {
if addPaddingForInitial {
headerLen := header.GetLength(p.version)
header.Length = protocol.ByteCount(header.PacketNumberLen) + protocol.MinInitialPacketSize - headerLen
} else {
// long header packets always use 4 byte packet number, so we never need to pad short payloads
length := protocol.ByteCount(sealer.Overhead()) + protocol.ByteCount(header.PacketNumberLen)
for _, frame := range frames {
length += frame.Length(p.version)
@ -453,19 +423,31 @@ func (p *packetPacker) writeAndSealPacket(
}
payloadStartIndex := buffer.Len()
// the Initial packet needs to be padded, so the last STREAM frame must have the data length present
if p.perspective == protocol.PerspectiveClient && header.Type == protocol.PacketTypeInitial {
lastFrame := frames[len(frames)-1]
if sf, ok := lastFrame.(*wire.StreamFrame); ok {
sf.DataLenPresent = true
}
}
for _, frame := range frames {
// write all frames but the last one
for _, frame := range frames[:len(frames)-1] {
if err := frame.Write(buffer, p.version); err != nil {
return nil, err
}
}
if addPadding {
lastFrame := frames[len(frames)-1]
if addPaddingForInitial {
// when appending padding, we need to make sure that the last STREAM frames has the data length set
if sf, ok := lastFrame.(*wire.StreamFrame); ok {
sf.DataLenPresent = true
}
} else {
payloadLen := buffer.Len() - payloadStartIndex + int(lastFrame.Length(p.version))
if paddingLen := 4 - int(header.PacketNumberLen) - payloadLen; paddingLen > 0 {
// Pad the packet such that packet number length + payload length is 4 bytes.
// This is needed to enable the peer to get a 16 byte sample for header protection.
buffer.Write(bytes.Repeat([]byte{0}, paddingLen))
}
}
if err := lastFrame.Write(buffer, p.version); err != nil {
return nil, err
}
if addPaddingForInitial {
paddingLen := protocol.MinInitialPacketSize - sealer.Overhead() - buffer.Len()
if paddingLen > 0 {
buffer.Write(bytes.Repeat([]byte{0}, paddingLen))
@ -484,14 +466,9 @@ func (p *packetPacker) writeAndSealPacket(
if num != header.PacketNumber {
return nil, errors.New("packetPacker BUG: Peeked and Popped packet numbers do not match")
}
p.hasSentPacket = true
return raw, nil
}
func (p *packetPacker) canSendData(encLevel protocol.EncryptionLevel) bool {
return encLevel == protocol.Encryption1RTT
}
func (p *packetPacker) ChangeDestConnectionID(connID protocol.ConnectionID) {
p.destConnID = connID
}

View File

@ -58,7 +58,6 @@ func (u *packetUnpacker) Unpack(headerBinary []byte, hdr *wire.ExtendedHeader, d
encryptionLevel = protocol.Encryption1RTT
}
if err != nil {
// Wrap err in quicError so that public reset is sent by session
return nil, qerr.Error(qerr.DecryptionFailure, err.Error())
}

View File

@ -128,6 +128,10 @@ func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener,
}
func listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*server, error) {
// TODO(#1655): only require that tls.Config.Certificates or tls.Config.GetCertificate is set
if tlsConf == nil || len(tlsConf.Certificates) == 0 {
return nil, errors.New("quic: Certificates not set in tls.Config")
}
config = populateServerConfig(config)
for _, v := range config.Versions {
if !protocol.IsValidVersion(v) {

View File

@ -114,9 +114,7 @@ type session struct {
receivedFirstPacket bool // since packet numbers start at 0, we can't use largestRcvdPacketNumber != 0 for this
receivedFirstForwardSecurePacket bool
// Used to calculate the next packet number from the truncated wire
// representation, and sent back in public reset packets
largestRcvdPacketNumber protocol.PacketNumber
largestRcvdPacketNumber protocol.PacketNumber // used to calculate the next packet number
sessionCreationTime time.Time
lastNetworkActivityTime time.Time
@ -905,12 +903,7 @@ func (s *session) maybeSendRetransmission() (bool, error) {
break
}
if retransmitPacket.EncryptionLevel != protocol.Encryption1RTT {
s.logger.Debugf("Dequeueing handshake retransmission for packet 0x%x", retransmitPacket.PacketNumber)
} else {
s.logger.Debugf("Dequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber)
}
s.logger.Debugf("Dequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber)
packets, err := s.packer.PackRetransmission(retransmitPacket)
if err != nil {
return false, err

12
vendor/github.com/lucas-clemente/sync-files.sh generated vendored Executable file
View File

@ -0,0 +1,12 @@
#!/bin/bash
rsync -rv "$GOPATH/src/github.com/lucas-clemente/quic-go/" "$GOPATH/src/v2ray.com/core/vendor/github.com/lucas-clemente/quic-go/"
find . -name "*_test.go" -delete
rm -rf ./quic-go/\.*
rm -rf ./quic-go/benchmark
rm -rf ./quic-go/docs
rm -rf ./quic-go/example
rm -rf ./quic-go/h2quic
rm -rf ./quic-go/integrationtests
rm -rf ./quic-go/vendor/golang\.org/
rm ./quic-go/vendor/vendor.json