diff --git a/vendor/github.com/lucas-clemente/quic-go/client.go b/vendor/github.com/lucas-clemente/quic-go/client.go index 71e72dce..280c3fcd 100644 --- a/vendor/github.com/lucas-clemente/quic-go/client.go +++ b/vendor/github.com/lucas-clemente/quic-go/client.go @@ -25,12 +25,9 @@ type client struct { // If it is started with Dial, we take a packet conn as a parameter. createdPacketConn bool - hostname string - packetHandlers packetHandlerManager - token []byte - numRetries int + token []byte versionNegotiated bool // has the server accepted our version receivedVersionNegotiationPacket bool @@ -159,13 +156,12 @@ func newClient( closeCallback func(protocol.ConnectionID), createdPacketConn bool, ) (*client, error) { - var hostname string - if tlsConf != nil { - hostname = tlsConf.ServerName + if tlsConf == nil { + tlsConf = &tls.Config{} } - if hostname == "" { + if tlsConf.ServerName == "" { var err error - hostname, _, err = net.SplitHostPort(host) + tlsConf.ServerName, _, err = net.SplitHostPort(host) if err != nil { return nil, err } @@ -186,7 +182,6 @@ func newClient( c := &client{ conn: &conn{pconn: pconn, currentAddr: remoteAddr}, createdPacketConn: createdPacketConn, - hostname: hostname, tlsConf: tlsConf, config: config, version: config.Versions[0], @@ -286,7 +281,7 @@ func (c *client) generateConnectionIDs() error { } func (c *client) dial(ctx context.Context) error { - c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.hostname, c.conn.LocalAddr(), c.conn.RemoteAddr(), c.srcConnID, c.destConnID, c.version) + c.logger.Infof("Starting new connection to %s (%s -> %s), source connection ID %s, destination connection ID %s, version %s", c.tlsConf.ServerName, c.conn.LocalAddr(), c.conn.RemoteAddr(), c.srcConnID, c.destConnID, c.version) var err error if c.version.UsesTLS() { @@ -324,7 +319,6 @@ func (c *client) dialTLS(ctx context.Context) error { return err } mintConf.ExtensionHandler = extHandler - mintConf.ServerName = c.hostname c.mintConf = mintConf if err := c.createNewTLSSession(extHandler.GetPeerParams(), c.version); err != nil { @@ -483,19 +477,18 @@ func (c *client) handleVersionNegotiationPacket(hdr *wire.Header) error { func (c *client) handleRetryPacket(hdr *wire.Header) { c.logger.Debugf("<- Received Retry") hdr.Log(c.logger) - // A server that performs multiple retries must use a source connection ID of at least 8 bytes. - // Only a server that won't send additional Retries can use shorter connection IDs. - if hdr.OrigDestConnectionID.Len() < protocol.MinConnectionIDLenInitial { - c.logger.Debugf("Received a Retry with a too short Original Destination Connection ID: %d bytes, must have at least %d bytes.", hdr.OrigDestConnectionID.Len(), protocol.MinConnectionIDLenInitial) - return - } if !hdr.OrigDestConnectionID.Equal(c.destConnID) { - c.logger.Debugf("Received spoofed Retry. Original Destination Connection ID: %s, expected: %s", hdr.OrigDestConnectionID, c.destConnID) + c.logger.Debugf("Ignoring spoofed Retry. Original Destination Connection ID: %s, expected: %s", hdr.OrigDestConnectionID, c.destConnID) return } - c.numRetries++ - if c.numRetries > protocol.MaxRetries { - c.session.destroy(qerr.CryptoTooManyRejects) + if hdr.SrcConnectionID.Equal(c.destConnID) { + c.logger.Debugf("Ignoring Retry, since the server didn't change the Source Connection ID.") + return + } + // If a token is already set, this means that we already received a Retry from the server. + // Ignore this Retry packet. + if len(c.token) > 0 { + c.logger.Debugf("Ignoring Retry, since a Retry was already received.") return } c.destConnID = hdr.SrcConnectionID @@ -513,7 +506,6 @@ func (c *client) createNewGQUICSession() error { sess, err := newClientSession( c.conn, runner, - c.hostname, c.version, c.destConnID, c.srcConnID, diff --git a/vendor/github.com/lucas-clemente/quic-go/crypto_stream.go b/vendor/github.com/lucas-clemente/quic-go/crypto_stream.go index a5ec4ecf..d51dc2ab 100644 --- a/vendor/github.com/lucas-clemente/quic-go/crypto_stream.go +++ b/vendor/github.com/lucas-clemente/quic-go/crypto_stream.go @@ -13,6 +13,7 @@ type cryptoStream interface { io.Reader io.Writer handleStreamFrame(*wire.StreamFrame) error + hasData() bool popStreamFrame(protocol.ByteCount) (*wire.StreamFrame, bool) closeForShutdown(error) setReadOffset(protocol.ByteCount) diff --git a/vendor/github.com/lucas-clemente/quic-go/example/client/main.go b/vendor/github.com/lucas-clemente/quic-go/example/client/main.go index 23f045c8..825b5ab7 100644 --- a/vendor/github.com/lucas-clemente/quic-go/example/client/main.go +++ b/vendor/github.com/lucas-clemente/quic-go/example/client/main.go @@ -16,6 +16,7 @@ import ( func main() { verbose := flag.Bool("v", false, "verbose") tls := flag.Bool("tls", false, "activate support for IETF QUIC (work in progress)") + quiet := flag.Bool("q", false, "don't print the data") flag.Parse() urls := flag.Args() @@ -57,8 +58,12 @@ func main() { if err != nil { panic(err) } - logger.Infof("Request Body:") - logger.Infof("%s", body.Bytes()) + if *quiet { + logger.Infof("Request Body: %d bytes", body.Len()) + } else { + logger.Infof("Request Body:") + logger.Infof("%s", body.Bytes()) + } wg.Done() }(addr) } diff --git a/vendor/github.com/lucas-clemente/quic-go/stream_framer.go b/vendor/github.com/lucas-clemente/quic-go/framer.go similarity index 55% rename from vendor/github.com/lucas-clemente/quic-go/stream_framer.go rename to vendor/github.com/lucas-clemente/quic-go/framer.go index aabfac9f..74ca8c45 100644 --- a/vendor/github.com/lucas-clemente/quic-go/stream_framer.go +++ b/vendor/github.com/lucas-clemente/quic-go/framer.go @@ -7,23 +7,25 @@ import ( "github.com/lucas-clemente/quic-go/internal/wire" ) -type streamFramer struct { +type framer struct { streamGetter streamGetter cryptoStream cryptoStream version protocol.VersionNumber - streamQueueMutex sync.Mutex - activeStreams map[protocol.StreamID]struct{} - streamQueue []protocol.StreamID - hasCryptoStreamData bool + streamQueueMutex sync.Mutex + activeStreams map[protocol.StreamID]struct{} + streamQueue []protocol.StreamID + + controlFrameMutex sync.Mutex + controlFrames []wire.Frame } -func newStreamFramer( +func newFramer( cryptoStream cryptoStream, streamGetter streamGetter, v protocol.VersionNumber, -) *streamFramer { - return &streamFramer{ +) *framer { + return &framer{ streamGetter: streamGetter, cryptoStream: cryptoStream, activeStreams: make(map[protocol.StreamID]struct{}), @@ -31,13 +33,32 @@ func newStreamFramer( } } -func (f *streamFramer) AddActiveStream(id protocol.StreamID) { - if id == f.version.CryptoStreamID() { // the crypto stream is handled separately - f.streamQueueMutex.Lock() - f.hasCryptoStreamData = true - f.streamQueueMutex.Unlock() - return +func (f *framer) QueueControlFrame(frame wire.Frame) { + f.controlFrameMutex.Lock() + f.controlFrames = append(f.controlFrames, frame) + f.controlFrameMutex.Unlock() +} + +func (f *framer) AppendControlFrames(frames []wire.Frame, maxLen protocol.ByteCount) ([]wire.Frame, protocol.ByteCount) { + var length protocol.ByteCount + f.controlFrameMutex.Lock() + for len(f.controlFrames) > 0 { + frame := f.controlFrames[len(f.controlFrames)-1] + frameLen := frame.Length(f.version) + if length+frameLen > maxLen { + break + } + frames = append(frames, frame) + length += frameLen + f.controlFrames = f.controlFrames[:len(f.controlFrames)-1] } + f.controlFrameMutex.Unlock() + return frames, length +} + +// AddActiveStream adds a stream that has data to write. +// It should not be used for the crypto stream. +func (f *framer) AddActiveStream(id protocol.StreamID) { f.streamQueueMutex.Lock() if _, ok := f.activeStreams[id]; !ok { f.streamQueue = append(f.streamQueue, id) @@ -46,29 +67,13 @@ func (f *streamFramer) AddActiveStream(id protocol.StreamID) { f.streamQueueMutex.Unlock() } -func (f *streamFramer) HasCryptoStreamData() bool { - f.streamQueueMutex.Lock() - hasCryptoStreamData := f.hasCryptoStreamData - f.streamQueueMutex.Unlock() - return hasCryptoStreamData -} - -func (f *streamFramer) PopCryptoStreamFrame(maxLen protocol.ByteCount) *wire.StreamFrame { - f.streamQueueMutex.Lock() - frame, hasMoreData := f.cryptoStream.popStreamFrame(maxLen) - f.hasCryptoStreamData = hasMoreData - f.streamQueueMutex.Unlock() - return frame -} - -func (f *streamFramer) PopStreamFrames(maxTotalLen protocol.ByteCount) []*wire.StreamFrame { - var currentLen protocol.ByteCount - var frames []*wire.StreamFrame +func (f *framer) AppendStreamFrames(frames []wire.Frame, maxLen protocol.ByteCount) []wire.Frame { + var length protocol.ByteCount f.streamQueueMutex.Lock() // pop STREAM frames, until less than MinStreamFrameSize bytes are left in the packet numActiveStreams := len(f.streamQueue) for i := 0; i < numActiveStreams; i++ { - if maxTotalLen-currentLen < protocol.MinStreamFrameSize { + if maxLen-length < protocol.MinStreamFrameSize { break } id := f.streamQueue[0] @@ -81,7 +86,7 @@ func (f *streamFramer) PopStreamFrames(maxTotalLen protocol.ByteCount) []*wire.S delete(f.activeStreams, id) continue } - frame, hasMoreData := str.popStreamFrame(maxTotalLen - currentLen) + frame, hasMoreData := str.popStreamFrame(maxLen - length) if hasMoreData { // put the stream back in the queue (at the end) f.streamQueue = append(f.streamQueue, id) } else { // no more data to send. Stream is not active any more @@ -91,7 +96,7 @@ func (f *streamFramer) PopStreamFrames(maxTotalLen protocol.ByteCount) []*wire.S continue } frames = append(frames, frame) - currentLen += frame.Length(f.version) + length += frame.Length(f.version) } f.streamQueueMutex.Unlock() return frames diff --git a/vendor/github.com/lucas-clemente/quic-go/h2quic/server.go b/vendor/github.com/lucas-clemente/quic-go/h2quic/server.go index 0d787bdd..cd9cbea2 100644 --- a/vendor/github.com/lucas-clemente/quic-go/h2quic/server.go +++ b/vendor/github.com/lucas-clemente/quic-go/h2quic/server.go @@ -141,7 +141,7 @@ func (s *Server) handleHeaderStream(session streamCreator) { // In this case, the session has already logged the error, so we don't // need to log it again. errorCode := qerr.InternalError - if qerr, ok := err.(*qerr.QuicError); !ok { + if qerr, ok := err.(*qerr.QuicError); ok { errorCode = qerr.ErrorCode s.logger.Errorf("error handling h2 request: %s", err.Error()) } diff --git a/vendor/github.com/lucas-clemente/quic-go/interface.go b/vendor/github.com/lucas-clemente/quic-go/interface.go index d7048097..c30bab2a 100644 --- a/vendor/github.com/lucas-clemente/quic-go/interface.go +++ b/vendor/github.com/lucas-clemente/quic-go/interface.go @@ -23,8 +23,6 @@ const ( VersionGQUIC43 = protocol.Version43 // VersionGQUIC44 is gQUIC version 44. VersionGQUIC44 = protocol.Version44 - // VersionMilestone0_10_0 uses TLS - VersionMilestone0_10_0 = protocol.VersionMilestone0_10_0 ) // A Cookie can be used to verify the ownership of the client address. diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go b/vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go index 4fdb8c36..58360437 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/ackhandler/sent_packet_handler.go @@ -148,6 +148,7 @@ func (h *sentPacketHandler) SentPacketsAsRetransmission(packets []*Packet, retra func (h *sentPacketHandler) sentPacketImpl(packet *Packet) bool /* isRetransmittable */ { for p := h.lastSentPacketNumber + 1; p < packet.PacketNumber; p++ { + h.logger.Debugf("Skipping packet number %#x", p) h.skippedPackets = append(h.skippedPackets, p) if len(h.skippedPackets) > protocol.MaxTrackedSkippedPackets { h.skippedPackets = h.skippedPackets[1:] @@ -633,7 +634,7 @@ func (h *sentPacketHandler) computeRTOTimeout() time.Duration { } rto = utils.MaxDuration(rto, minRTOTimeout) // Exponential backoff - rto = rto << h.rtoCount + rto <<= h.rtoCount return utils.MinDuration(rto, maxRTOTimeout) } diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go b/vendor/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go index b9f67e6c..33ef491f 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/congestion/cubic_sender.go @@ -193,7 +193,7 @@ func (c *cubicSender) OnPacketLost( if c.congestionWindow >= 2*c.initialCongestionWindow { c.minSlowStartExitWindow = c.congestionWindow / 2 } - c.congestionWindow = c.congestionWindow - protocol.DefaultTCPMSS + c.congestionWindow -= protocol.DefaultTCPMSS } else if c.reno { c.congestionWindow = protocol.ByteCount(float32(c.congestionWindow) * c.RenoBeta()) } else { diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/cert_chain.go b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/cert_chain.go index 0c728fd2..45af2952 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/cert_chain.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/cert_chain.go @@ -56,8 +56,7 @@ func (c *certChain) GetLeafCert(sni string) ([]byte, error) { } func (c *certChain) getCertForSNI(sni string) (*tls.Certificate, error) { - conf := c.config - conf, err := maybeGetConfigForClient(conf, sni) + conf, err := maybeGetConfigForClient(c.config, sni) if err != nil { return nil, err } @@ -107,7 +106,13 @@ func maybeGetConfigForClient(c *tls.Config, sni string) (*tls.Config, error) { if c.GetConfigForClient == nil { return c, nil } - return c.GetConfigForClient(&tls.ClientHelloInfo{ - ServerName: sni, - }) + confForClient, err := c.GetConfigForClient(&tls.ClientHelloInfo{ServerName: sni}) + if err != nil { + return nil, err + } + // if GetConfigForClient returns nil, use the original config + if confForClient == nil { + return c, nil + } + return confForClient, nil } diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/hkdf.go b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/hkdf.go new file mode 100644 index 00000000..4c6af289 --- /dev/null +++ b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/hkdf.go @@ -0,0 +1,56 @@ +package crypto + +import ( + "crypto" + "crypto/hmac" + "encoding/binary" +) + +// copied from https://github.com/cloudflare/tls-tris/blob/master/hkdf.go +func hkdfExtract(hash crypto.Hash, secret, salt []byte) []byte { + if salt == nil { + salt = make([]byte, hash.Size()) + } + if secret == nil { + secret = make([]byte, hash.Size()) + } + extractor := hmac.New(hash.New, salt) + extractor.Write(secret) + return extractor.Sum(nil) +} + +// copied from https://github.com/cloudflare/tls-tris/blob/master/hkdf.go +func hkdfExpand(hash crypto.Hash, prk, info []byte, l int) []byte { + var ( + expander = hmac.New(hash.New, prk) + res = make([]byte, l) + counter = byte(1) + prev []byte + ) + + if l > 255*expander.Size() { + panic("hkdf: requested too much output") + } + + p := res + for len(p) > 0 { + expander.Reset() + expander.Write(prev) + expander.Write(info) + expander.Write([]byte{counter}) + prev = expander.Sum(prev[:0]) + counter++ + n := copy(p, prev) + p = p[n:] + } + + return res +} + +func qhkdfExpand(secret []byte, label string, length int) []byte { + qlabel := make([]byte, 2+1+5+len(label)) + binary.BigEndian.PutUint16(qlabel[0:2], uint16(length)) + qlabel[2] = uint8(5 + len(label)) + copy(qlabel[3:], []byte("QUIC "+label)) + return hkdfExpand(crypto.SHA256, secret, qlabel, length) +} diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/key_derivation.go b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/key_derivation.go index 8aa187ff..fe71ab96 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/key_derivation.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/key_derivation.go @@ -1,9 +1,6 @@ package crypto import ( - "crypto" - "encoding/binary" - "github.com/bifurcation/mint" "github.com/lucas-clemente/quic-go/internal/protocol" ) @@ -19,14 +16,6 @@ type TLSExporter interface { ComputeExporter(label string, context []byte, keyLength int) ([]byte, error) } -func qhkdfExpand(secret []byte, label string, length int) []byte { - qlabel := make([]byte, 2+1+5+len(label)) - binary.BigEndian.PutUint16(qlabel[0:2], uint16(length)) - qlabel[2] = uint8(5 + len(label)) - copy(qlabel[3:], []byte("QUIC "+label)) - return mint.HkdfExpand(crypto.SHA256, secret, qlabel, length) -} - // DeriveAESKeys derives the AES keys and creates a matching AES-GCM AEAD instance func DeriveAESKeys(tls TLSExporter, pers protocol.Perspective) (AEAD, error) { var myLabel, otherLabel string diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go index 4abc6229..17148fdb 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/crypto/null_aead_aesgcm.go @@ -3,7 +3,6 @@ package crypto import ( "crypto" - "github.com/bifurcation/mint" "github.com/lucas-clemente/quic-go/internal/protocol" ) @@ -28,7 +27,7 @@ func newNullAEADAESGCM(connectionID protocol.ConnectionID, pers protocol.Perspec } func computeSecrets(connID protocol.ConnectionID) (clientSecret, serverSecret []byte) { - handshakeSecret := mint.HkdfExtract(crypto.SHA256, quicVersion1Salt, connID) + handshakeSecret := hkdfExtract(crypto.SHA256, connID, quicVersion1Salt) clientSecret = qhkdfExpand(handshakeSecret, "client hs", crypto.SHA256.Size()) serverSecret = qhkdfExpand(handshakeSecret, "server hs", crypto.SHA256.Size()) return diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go b/vendor/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go index 6687b834..655449c7 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/handshake/crypto_setup_client.go @@ -69,10 +69,9 @@ var ( // NewCryptoSetupClient creates a new CryptoSetup instance for a client func NewCryptoSetupClient( cryptoStream io.ReadWriter, - hostname string, connID protocol.ConnectionID, version protocol.VersionNumber, - tlsConfig *tls.Config, + tlsConf *tls.Config, params *TransportParameters, paramsChan chan<- TransportParameters, handshakeEvent chan<- struct{}, @@ -87,10 +86,10 @@ func NewCryptoSetupClient( divNonceChan := make(chan struct{}) cs := &cryptoSetupClient{ cryptoStream: cryptoStream, - hostname: hostname, + hostname: tlsConf.ServerName, connID: connID, version: version, - certManager: crypto.NewCertManager(tlsConfig), + certManager: crypto.NewCertManager(tlsConf), params: params, keyDerivation: crypto.DeriveQuicCryptoAESKeys, nullAEAD: nullAEAD, diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go b/vendor/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go index 9ed0aeb5..c94e31f7 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/handshake/transport_parameters.go @@ -3,8 +3,8 @@ package handshake import ( "bytes" "encoding/binary" - "errors" "fmt" + "sort" "time" "github.com/lucas-clemente/quic-go/internal/protocol" @@ -97,16 +97,18 @@ func (p *TransportParameters) getHelloMap() map[Tag][]byte { } func (p *TransportParameters) unmarshal(data []byte) error { - var foundIdleTimeout bool + // needed to check that every parameter is only sent at most once + var parameterIDs []transportParameterID for len(data) >= 4 { - paramID := binary.BigEndian.Uint16(data[:2]) + paramID := transportParameterID(binary.BigEndian.Uint16(data[:2])) paramLen := int(binary.BigEndian.Uint16(data[2:4])) data = data[4:] if len(data) < paramLen { return fmt.Errorf("remaining length (%d) smaller than parameter length (%d)", len(data), paramLen) } - switch transportParameterID(paramID) { + parameterIDs = append(parameterIDs, paramID) + switch paramID { case initialMaxStreamDataParameterID: if paramLen != 4 { return fmt.Errorf("wrong length for initial_max_stream_data: %d (expected 4)", paramLen) @@ -128,7 +130,6 @@ func (p *TransportParameters) unmarshal(data []byte) error { } p.MaxUniStreams = binary.BigEndian.Uint16(data[:2]) case idleTimeoutParameterID: - foundIdleTimeout = true if paramLen != 2 { return fmt.Errorf("wrong length for idle_timeout: %d (expected 2)", paramLen) } @@ -156,12 +157,17 @@ func (p *TransportParameters) unmarshal(data []byte) error { data = data[paramLen:] } + // check that every transport parameter was sent at most once + sort.Slice(parameterIDs, func(i, j int) bool { return parameterIDs[i] < parameterIDs[j] }) + for i := 0; i < len(parameterIDs)-1; i++ { + if parameterIDs[i] == parameterIDs[i+1] { + return fmt.Errorf("received duplicate transport parameter %#x", parameterIDs[i]) + } + } + if len(data) != 0 { return fmt.Errorf("should have read all data. Still have %d bytes", len(data)) } - if !foundIdleTimeout { - return errors.New("missing parameter") - } return nil } diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/mocks/mockgen.go b/vendor/github.com/lucas-clemente/quic-go/internal/mocks/mockgen.go index 5bfcdc22..b01e97e4 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/mocks/mockgen.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/mocks/mockgen.go @@ -1,6 +1,7 @@ package mocks //go:generate sh -c "../mockgen_internal.sh mocks tls_extension_handler.go github.com/lucas-clemente/quic-go/internal/handshake TLSExtensionHandler" +//go:generate sh -c "../mockgen_internal.sh mocks sealer.go github.com/lucas-clemente/quic-go/internal/handshake Sealer" //go:generate sh -c "../mockgen_internal.sh mocks stream_flow_controller.go github.com/lucas-clemente/quic-go/internal/flowcontrol StreamFlowController" //go:generate sh -c "../mockgen_internal.sh mockackhandler ackhandler/sent_packet_handler.go github.com/lucas-clemente/quic-go/internal/ackhandler SentPacketHandler" //go:generate sh -c "../mockgen_internal.sh mockackhandler ackhandler/received_packet_handler.go github.com/lucas-clemente/quic-go/internal/ackhandler ReceivedPacketHandler" diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/mocks/sealer.go b/vendor/github.com/lucas-clemente/quic-go/internal/mocks/sealer.go new file mode 100644 index 00000000..8b2d1f6e --- /dev/null +++ b/vendor/github.com/lucas-clemente/quic-go/internal/mocks/sealer.go @@ -0,0 +1,59 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/lucas-clemente/quic-go/internal/handshake (interfaces: Sealer) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + protocol "github.com/lucas-clemente/quic-go/internal/protocol" +) + +// MockSealer is a mock of Sealer interface +type MockSealer struct { + ctrl *gomock.Controller + recorder *MockSealerMockRecorder +} + +// MockSealerMockRecorder is the mock recorder for MockSealer +type MockSealerMockRecorder struct { + mock *MockSealer +} + +// NewMockSealer creates a new mock instance +func NewMockSealer(ctrl *gomock.Controller) *MockSealer { + mock := &MockSealer{ctrl: ctrl} + mock.recorder = &MockSealerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockSealer) EXPECT() *MockSealerMockRecorder { + return m.recorder +} + +// Overhead mocks base method +func (m *MockSealer) Overhead() int { + ret := m.ctrl.Call(m, "Overhead") + ret0, _ := ret[0].(int) + return ret0 +} + +// Overhead indicates an expected call of Overhead +func (mr *MockSealerMockRecorder) Overhead() *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Overhead", reflect.TypeOf((*MockSealer)(nil).Overhead)) +} + +// Seal mocks base method +func (m *MockSealer) Seal(arg0, arg1 []byte, arg2 protocol.PacketNumber, arg3 []byte) []byte { + ret := m.ctrl.Call(m, "Seal", arg0, arg1, arg2, arg3) + ret0, _ := ret[0].([]byte) + return ret0 +} + +// Seal indicates an expected call of Seal +func (mr *MockSealerMockRecorder) Seal(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Seal", reflect.TypeOf((*MockSealer)(nil).Seal), arg0, arg1, arg2, arg3) +} diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/protocol/server_parameters.go b/vendor/github.com/lucas-clemente/quic-go/internal/protocol/server_parameters.go index aa61b3d7..aa92c822 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/protocol/server_parameters.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/protocol/server_parameters.go @@ -149,6 +149,3 @@ const MinPacingDelay time.Duration = 100 * time.Microsecond // DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections // if no other value is configured. const DefaultConnectionIDLength = 4 - -// MaxRetries is the maximum number of Retries a client will do before failing the connection. -const MaxRetries = 3 diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/protocol/version.go b/vendor/github.com/lucas-clemente/quic-go/internal/protocol/version.go index 9e1963dc..299c6fcc 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/protocol/version.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/protocol/version.go @@ -24,8 +24,6 @@ const ( VersionTLS VersionNumber = 101 VersionWhatever VersionNumber = 0 // for when the version doesn't matter VersionUnknown VersionNumber = math.MaxUint32 - - VersionMilestone0_10_0 VersionNumber = 0x51474f02 ) // SupportedVersions lists the versions that the server supports @@ -38,7 +36,7 @@ var SupportedVersions = []VersionNumber{ // IsValidVersion says if the version is known to quic-go func IsValidVersion(v VersionNumber) bool { - return v == VersionTLS || v == VersionMilestone0_10_0 || IsSupportedVersion(SupportedVersions, v) + return v == VersionTLS || IsSupportedVersion(SupportedVersions, v) } // UsesTLS says if this QUIC version uses TLS 1.3 for the handshake @@ -52,8 +50,6 @@ func (vn VersionNumber) String() string { return "whatever" case VersionUnknown: return "unknown" - case VersionMilestone0_10_0: - return "quic-go Milestone 0.10.0" case VersionTLS: return "TLS dev version (WIP)" default: diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/utils/timer.go b/vendor/github.com/lucas-clemente/quic-go/internal/utils/timer.go index 20eaacd0..1fefc6ec 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/utils/timer.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/utils/timer.go @@ -1,6 +1,9 @@ package utils -import "time" +import ( + "math" + "time" +) // A Timer wrapper that behaves correctly when resetting type Timer struct { @@ -11,7 +14,7 @@ type Timer struct { // NewTimer creates a new timer that is not set func NewTimer() *Timer { - return &Timer{t: time.NewTimer(0)} + return &Timer{t: time.NewTimer(time.Duration(math.MaxInt64))} } // Chan returns the channel of the wrapped timer @@ -31,7 +34,9 @@ func (t *Timer) Reset(deadline time.Time) { if !t.t.Stop() && !t.read { <-t.t.C } - t.t.Reset(time.Until(deadline)) + if !deadline.IsZero() { + t.t.Reset(time.Until(deadline)) + } t.read = false t.deadline = deadline diff --git a/vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go b/vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go index 00759db4..8eeb4001 100644 --- a/vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go +++ b/vendor/github.com/lucas-clemente/quic-go/internal/wire/ack_frame.go @@ -19,23 +19,17 @@ type AckFrame struct { DelayTime time.Duration } -func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { - return parseAckOrAckEcnFrame(r, false, version) -} - -func parseAckEcnFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { - return parseAckOrAckEcnFrame(r, true, version) -} - // parseAckFrame reads an ACK frame -func parseAckOrAckEcnFrame(r *bytes.Reader, ecn bool, version protocol.VersionNumber) (*AckFrame, error) { +func parseAckFrame(r *bytes.Reader, version protocol.VersionNumber) (*AckFrame, error) { if !version.UsesIETFFrameFormat() { return parseAckFrameLegacy(r, version) } - if _, err := r.ReadByte(); err != nil { + typeByte, err := r.ReadByte() + if err != nil { return nil, err } + ecn := typeByte&0x1 > 0 frame := &AckFrame{} @@ -50,14 +44,6 @@ func parseAckOrAckEcnFrame(r *bytes.Reader, ecn bool, version protocol.VersionNu } frame.DelayTime = time.Duration(delay*1< 0 || len(streamFrames) > 0 { var frames []wire.Frame - var payloadLength protocol.ByteCount + var length protocol.ByteCount header := p.getHeader(encLevel) headerLength, err := header.GetLength(p.version) @@ -182,48 +192,23 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP } maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength - // for gQUIC: add a STOP_WAITING for *every* retransmission - if p.version.UsesStopWaitingFrames() { - if p.stopWaiting == nil { - return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame") - } - // create a new StopWaitingFrame, since we might need to send more than one packet as a retransmission - swf := &wire.StopWaitingFrame{ - LeastUnacked: p.stopWaiting.LeastUnacked, - PacketNumber: header.PacketNumber, - PacketNumberLen: header.PacketNumberLen, - } - payloadLength += swf.Length(p.version) - frames = append(frames, swf) - } - for len(controlFrames) > 0 { frame := controlFrames[0] - length := frame.Length(p.version) - if payloadLength+length > maxSize { + frameLen := frame.Length(p.version) + if length+frameLen > maxSize { break } - payloadLength += length + length += frameLen frames = append(frames, frame) controlFrames = controlFrames[1:] } - // 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 StreamFrames 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 - // for gQUIC STREAM frames, DataLen is always 2 bytes - // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes - if p.version.UsesIETFFrameFormat() { - maxSize++ - } else { - maxSize += 2 - } - for len(streamFrames) > 0 && payloadLength+protocol.MinStreamFrameSize < maxSize { - // TODO: optimize by setting DataLenPresent = false on all but the last STREAM frame + for len(streamFrames) > 0 && length+protocol.MinStreamFrameSize < maxSize { frame := streamFrames[0] + frame.DataLenPresent = false frameToAdd := frame - sf, err := frame.MaybeSplitOffFrame(maxSize-payloadLength, p.version) + sf, err := frame.MaybeSplitOffFrame(maxSize-length, p.version) if err != nil { return nil, err } @@ -232,7 +217,8 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP } else { streamFrames = streamFrames[1:] } - payloadLength += frameToAdd.Length(p.version) + frame.DataLenPresent = true + length += frameToAdd.Length(p.version) frames = append(frames, frameToAdd) } if sf, ok := frames[len(frames)-1].(*wire.StreamFrame); ok { @@ -249,7 +235,6 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP encryptionLevel: encLevel, }) } - p.stopWaiting = nil return packets, nil } @@ -265,24 +250,11 @@ func (p *packetPacker) packHandshakeRetransmission(packet *ackhandler.Packet) (* } header := p.getHeader(packet.EncryptionLevel) header.Type = packet.PacketType - var frames []wire.Frame - if p.version.UsesStopWaitingFrames() { // for gQUIC: pack a STOP_WAITING first - if p.stopWaiting == nil { - return nil, errors.New("PacketPacker BUG: Handshake retransmissions must contain a STOP_WAITING frame") - } - swf := p.stopWaiting - swf.PacketNumber = header.PacketNumber - swf.PacketNumberLen = header.PacketNumberLen - p.stopWaiting = nil - frames = append([]wire.Frame{swf}, packet.Frames...) - } else { - frames = packet.Frames - } - raw, err := p.writeAndSealPacket(header, frames, sealer) + raw, err := p.writeAndSealPacket(header, packet.Frames, sealer) return &packedPacket{ header: header, raw: raw, - frames: frames, + frames: packet.Frames, encryptionLevel: packet.EncryptionLevel, }, err } @@ -290,13 +262,16 @@ func (p *packetPacker) packHandshakeRetransmission(packet *ackhandler.Packet) (* // 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) { - hasCryptoStreamFrame := p.streams.HasCryptoStreamData() - // if this is the first packet to be send, make sure it contains stream data - if !p.hasSentPacket && !hasCryptoStreamFrame { - return nil, nil + packet, err := p.maybePackCryptoPacket() + if err != nil { + return nil, err } - if hasCryptoStreamFrame { - return p.packCryptoPacket() + 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() @@ -306,54 +281,45 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) { if err != nil { return nil, err } - if p.stopWaiting != nil { - p.stopWaiting.PacketNumber = header.PacketNumber - p.stopWaiting.PacketNumberLen = header.PacketNumberLen - } maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength - payloadFrames, err := p.composeNextPacket(maxSize, p.canSendData(encLevel)) + frames, err := p.composeNextPacket(maxSize, p.canSendData(encLevel)) if err != nil { return nil, err } // Check if we have enough frames to send - if len(payloadFrames) == 0 { + if len(frames) == 0 { return nil, nil } - // Don't send out packets that only contain a StopWaitingFrame - if len(payloadFrames) == 1 && p.stopWaiting != nil { - return nil, nil - } - if p.ackFrame != nil { - // check if this packet only contains an ACK (and maybe a STOP_WAITING) - if len(payloadFrames) == 1 || (p.stopWaiting != nil && len(payloadFrames) == 2) { - if p.numNonRetransmittableAcks >= protocol.MaxNonRetransmittableAcks { - payloadFrames = append(payloadFrames, &wire.PingFrame{}) - p.numNonRetransmittableAcks = 0 - } else { - p.numNonRetransmittableAcks++ - } - } else { + // check if this packet only contains an ACK + if !ackhandler.HasRetransmittableFrames(frames) { + if p.numNonRetransmittableAcks >= protocol.MaxNonRetransmittableAcks { + frames = append(frames, &wire.PingFrame{}) p.numNonRetransmittableAcks = 0 + } else { + p.numNonRetransmittableAcks++ } + } else { + p.numNonRetransmittableAcks = 0 } - p.stopWaiting = nil - p.ackFrame = nil - raw, err := p.writeAndSealPacket(header, payloadFrames, sealer) + raw, err := p.writeAndSealPacket(header, frames, sealer) if err != nil { return nil, err } return &packedPacket{ header: header, raw: raw, - frames: payloadFrames, + frames: frames, encryptionLevel: encLevel, }, nil } -func (p *packetPacker) packCryptoPacket() (*packedPacket, error) { +func (p *packetPacker) maybePackCryptoPacket() (*packedPacket, error) { + if !p.cryptoStream.hasData() { + return nil, nil + } encLevel, sealer := p.cryptoSetup.GetSealerForCryptoStream() header := p.getHeader(encLevel) headerLength, err := header.GetLength(p.version) @@ -361,7 +327,7 @@ func (p *packetPacker) packCryptoPacket() (*packedPacket, error) { return nil, err } maxLen := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - protocol.NonForwardSecurePacketSizeReduction - headerLength - sf := p.streams.PopCryptoStreamFrame(maxLen) + sf, _ := p.cryptoStream.popStreamFrame(maxLen) sf.DataLenPresent = false frames := []wire.Frame{sf} raw, err := p.writeAndSealPacket(header, frames, sealer) @@ -380,74 +346,37 @@ func (p *packetPacker) composeNextPacket( maxFrameSize protocol.ByteCount, canSendStreamFrames bool, ) ([]wire.Frame, error) { - var payloadLength protocol.ByteCount - var payloadFrames []wire.Frame + var length protocol.ByteCount + var frames []wire.Frame - // STOP_WAITING and ACK will always fit - if p.ackFrame != nil { // ACKs need to go first, so that the sentPacketHandler will recognize them - payloadFrames = append(payloadFrames, p.ackFrame) - l := p.ackFrame.Length(p.version) - payloadLength += l - } - if p.stopWaiting != nil { // a STOP_WAITING will only be queued when using gQUIC - payloadFrames = append(payloadFrames, p.stopWaiting) - payloadLength += p.stopWaiting.Length(p.version) + // ACKs need to go first, so that the sentPacketHandler will recognize them + if ack := p.acks.GetAckFrame(); ack != nil { + frames = append(frames, ack) + length += ack.Length(p.version) } - p.controlFrameMutex.Lock() - for len(p.controlFrames) > 0 { - frame := p.controlFrames[len(p.controlFrames)-1] - length := frame.Length(p.version) - if payloadLength+length > maxFrameSize { - break - } - payloadFrames = append(payloadFrames, frame) - payloadLength += length - p.controlFrames = p.controlFrames[:len(p.controlFrames)-1] - } - p.controlFrameMutex.Unlock() - - if payloadLength > maxFrameSize { - return nil, fmt.Errorf("Packet Packer BUG: packet payload (%d) too large (%d)", payloadLength, maxFrameSize) - } + var lengthAdded protocol.ByteCount + frames, lengthAdded = p.framer.AppendControlFrames(frames, maxFrameSize-length) + length += lengthAdded if !canSendStreamFrames { - return payloadFrames, nil + 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 StreamFrames that have the DataLen set + // 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 - // for gQUIC STREAM frames, DataLen is always 2 bytes - // for IETF draft style STREAM frames, the length is encoded to either 1 or 2 bytes - if p.version.UsesIETFFrameFormat() { - maxFrameSize++ - } else { - maxFrameSize += 2 - } + // the length is encoded to either 1 or 2 bytes + maxFrameSize++ - fs := p.streams.PopStreamFrames(maxFrameSize - payloadLength) - if len(fs) != 0 { - fs[len(fs)-1].DataLenPresent = false - } - - for _, f := range fs { - payloadFrames = append(payloadFrames, f) - } - return payloadFrames, nil -} - -func (p *packetPacker) QueueControlFrame(frame wire.Frame) { - switch f := frame.(type) { - case *wire.StopWaitingFrame: - p.stopWaiting = f - case *wire.AckFrame: - p.ackFrame = f - default: - p.controlFrameMutex.Lock() - p.controlFrames = append(p.controlFrames, f) - p.controlFrameMutex.Unlock() + frames = p.framer.AppendStreamFrames(frames, maxFrameSize-length) + if len(frames) > 0 { + lastFrame := frames[len(frames)-1] + if sf, ok := lastFrame.(*wire.StreamFrame); ok { + sf.DataLenPresent = false + } } + return frames, nil } func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header { @@ -455,17 +384,15 @@ func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header packetNumberLen := p.getPacketNumberLen(pnum) header := &wire.Header{ - PacketNumber: pnum, - PacketNumberLen: packetNumberLen, - Version: p.version, + PacketNumber: pnum, + PacketNumberLen: packetNumberLen, + Version: p.version, + DestConnectionID: p.destConnID, } - if p.version.UsesIETFHeaderFormat() && encLevel != protocol.EncryptionForwardSecure { + if encLevel != protocol.EncryptionForwardSecure { header.IsLongHeader = true header.SrcConnectionID = p.srcConnID - if !p.version.UsesVarintPacketNumbers() { - header.PacketNumberLen = protocol.PacketNumberLen4 - } // Set the payload len to maximum size. // Since it is encoded as a varint, this guarantees us that the header will end up at most as big as GetLength() returns. header.PayloadLen = p.maxPacketSize @@ -477,24 +404,12 @@ func (p *packetPacker) getHeader(encLevel protocol.EncryptionLevel) *wire.Header } } - if !p.omitConnectionID || encLevel != protocol.EncryptionForwardSecure { - header.DestConnectionID = p.destConnID - } - if !p.version.UsesTLS() { - if p.perspective == protocol.PerspectiveServer && encLevel == protocol.EncryptionSecure { - header.Type = protocol.PacketType0RTT - header.DiversificationNonce = p.divNonce - } - if p.perspective == protocol.PerspectiveClient && encLevel != protocol.EncryptionForwardSecure { - header.VersionFlag = true - } - } return header } func (p *packetPacker) writeAndSealPacket( header *wire.Header, - payloadFrames []wire.Frame, + frames []wire.Frame, sealer handshake.Sealer, ) ([]byte, error) { raw := *getPacketBuffer() @@ -507,7 +422,7 @@ func (p *packetPacker) writeAndSealPacket( header.PayloadLen = protocol.ByteCount(protocol.MinInitialPacketSize) - headerLen } else { payloadLen := protocol.ByteCount(sealer.Overhead()) - for _, frame := range payloadFrames { + for _, frame := range frames { payloadLen += frame.Length(p.version) } header.PayloadLen = payloadLen @@ -521,18 +436,17 @@ func (p *packetPacker) writeAndSealPacket( // the Initial packet needs to be padded, so the last STREAM frame must have the data length present if header.Type == protocol.PacketTypeInitial { - lastFrame := payloadFrames[len(payloadFrames)-1] + lastFrame := frames[len(frames)-1] if sf, ok := lastFrame.(*wire.StreamFrame); ok { sf.DataLenPresent = true } } - for _, frame := range payloadFrames { + for _, frame := range frames { if err := frame.Write(buffer, p.version); err != nil { return nil, err } } - // if this is an IETF QUIC Initial packet, we need to pad it to fulfill the minimum size requirement - // in gQUIC, padding is handled in the CHLO + // if this is an Initial packet, we need to pad it to fulfill the minimum size requirement if header.Type == protocol.PacketTypeInitial { paddingLen := protocol.MinInitialPacketSize - sealer.Overhead() - buffer.Len() if paddingLen > 0 { @@ -563,14 +477,12 @@ func (p *packetPacker) canSendData(encLevel protocol.EncryptionLevel) bool { return encLevel == protocol.EncryptionForwardSecure } -func (p *packetPacker) SetOmitConnectionID() { - p.omitConnectionID = true -} - func (p *packetPacker) ChangeDestConnectionID(connID protocol.ConnectionID) { p.destConnID = connID } -func (p *packetPacker) SetMaxPacketSize(size protocol.ByteCount) { - p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, size) +func (p *packetPacker) HandleTransportParameters(params *handshake.TransportParameters) { + if params.MaxPacketSize != 0 { + p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, params.MaxPacketSize) + } } diff --git a/vendor/github.com/lucas-clemente/quic-go/packet_packer_legacy.go b/vendor/github.com/lucas-clemente/quic-go/packet_packer_legacy.go new file mode 100644 index 00000000..2fb20ed5 --- /dev/null +++ b/vendor/github.com/lucas-clemente/quic-go/packet_packer_legacy.go @@ -0,0 +1,455 @@ +package quic + +import ( + "bytes" + "errors" + "fmt" + "net" + + "github.com/lucas-clemente/quic-go/internal/ackhandler" + "github.com/lucas-clemente/quic-go/internal/handshake" + "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/wire" +) + +// sentAndReceivedPacketManager is only needed until STOP_WAITING is removed +type sentAndReceivedPacketManager struct { + ackhandler.SentPacketHandler + ackhandler.ReceivedPacketHandler +} + +var _ ackFrameSource = &sentAndReceivedPacketManager{} + +type packetPackerLegacy struct { + destConnID protocol.ConnectionID + srcConnID protocol.ConnectionID + + perspective protocol.Perspective + version protocol.VersionNumber + cryptoSetup sealingManager + + divNonce []byte + + packetNumberGenerator *packetNumberGenerator + getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen + cryptoStream cryptoStream + framer frameSource + acks ackFrameSource + + omitConnectionID bool + maxPacketSize protocol.ByteCount + hasSentPacket bool // has the packetPacker already sent a packet + numNonRetransmittableAcks int +} + +var _ packer = &packetPackerLegacy{} + +func newPacketPackerLegacy( + destConnID protocol.ConnectionID, + srcConnID protocol.ConnectionID, + getPacketNumberLen func(protocol.PacketNumber) protocol.PacketNumberLen, + remoteAddr net.Addr, // only used for determining the max packet size + divNonce []byte, + cryptoStream cryptoStream, + cryptoSetup sealingManager, + framer frameSource, + acks ackFrameSource, + perspective protocol.Perspective, + version protocol.VersionNumber, +) *packetPackerLegacy { + return &packetPackerLegacy{ + cryptoStream: cryptoStream, + cryptoSetup: cryptoSetup, + divNonce: divNonce, + destConnID: destConnID, + srcConnID: srcConnID, + perspective: perspective, + version: version, + framer: framer, + acks: acks, + getPacketNumberLen: getPacketNumberLen, + packetNumberGenerator: newPacketNumberGenerator(1, protocol.SkipPacketAveragePeriodLength), + maxPacketSize: getMaxPacketSize(remoteAddr), + } +} + +// PackConnectionClose packs a packet that ONLY contains a ConnectionCloseFrame +func (p *packetPackerLegacy) PackConnectionClose(ccf *wire.ConnectionCloseFrame) (*packedPacket, error) { + frames := []wire.Frame{ccf} + encLevel, sealer := p.cryptoSetup.GetSealer() + header := p.getHeader(encLevel) + raw, err := p.writeAndSealPacket(header, frames, sealer) + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, err +} + +func (p *packetPackerLegacy) MaybePackAckPacket() (*packedPacket, error) { + ack := p.acks.GetAckFrame() + if ack == nil { + return nil, nil + } + encLevel, sealer := p.cryptoSetup.GetSealer() + header := p.getHeader(encLevel) + frames := []wire.Frame{ack} + // add a STOP_WAITING frame, if necessary + if p.version.UsesStopWaitingFrames() { + if swf := p.acks.GetStopWaitingFrame(false); swf != nil { + swf.PacketNumber = header.PacketNumber + swf.PacketNumberLen = header.PacketNumberLen + frames = append(frames, swf) + } + } + raw, err := p.writeAndSealPacket(header, frames, sealer) + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, err +} + +// PackRetransmission packs a retransmission +// 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 *packetPackerLegacy) PackRetransmission(packet *ackhandler.Packet) ([]*packedPacket, error) { + if packet.EncryptionLevel != protocol.EncryptionForwardSecure { + p, err := p.packHandshakeRetransmission(packet) + return []*packedPacket{p}, err + } + + var controlFrames []wire.Frame + var streamFrames []*wire.StreamFrame + for _, f := range packet.Frames { + if sf, ok := f.(*wire.StreamFrame); ok { + sf.DataLenPresent = true + streamFrames = append(streamFrames, sf) + } else { + controlFrames = append(controlFrames, f) + } + } + + var packets []*packedPacket + encLevel, sealer := p.cryptoSetup.GetSealer() + var swf *wire.StopWaitingFrame + // add a STOP_WAITING for *every* retransmission + if p.version.UsesStopWaitingFrames() { + swf = p.acks.GetStopWaitingFrame(true) + } + for len(controlFrames) > 0 || len(streamFrames) > 0 { + var frames []wire.Frame + var length protocol.ByteCount + + header := p.getHeader(encLevel) + headerLength, err := header.GetLength(p.version) + if err != nil { + return nil, err + } + maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength + + if p.version.UsesStopWaitingFrames() { + // create a new STOP_WAIITNG Frame, since we might need to send more than one packet as a retransmission + stopWaitingFrame := &wire.StopWaitingFrame{ + LeastUnacked: swf.LeastUnacked, + PacketNumber: header.PacketNumber, + PacketNumberLen: header.PacketNumberLen, + } + length += stopWaitingFrame.Length(p.version) + frames = append(frames, stopWaitingFrame) + } + + for len(controlFrames) > 0 { + frame := controlFrames[0] + frameLen := frame.Length(p.version) + if length+frameLen > maxSize { + break + } + length += frameLen + frames = append(frames, frame) + controlFrames = controlFrames[1:] + } + + // 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 StreamFrames 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 + maxSize += 2 + + for len(streamFrames) > 0 && length+protocol.MinStreamFrameSize < maxSize { + frame := streamFrames[0] + frameToAdd := frame + + sf, err := frame.MaybeSplitOffFrame(maxSize-length, p.version) + if err != nil { + return nil, err + } + if sf != nil { + frameToAdd = sf + } else { + streamFrames = streamFrames[1:] + } + length += frameToAdd.Length(p.version) + frames = append(frames, frameToAdd) + } + if sf, ok := frames[len(frames)-1].(*wire.StreamFrame); ok { + sf.DataLenPresent = false + } + raw, err := p.writeAndSealPacket(header, frames, sealer) + if err != nil { + return nil, err + } + packets = append(packets, &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }) + } + return packets, nil +} + +// packHandshakeRetransmission retransmits a handshake packet, that was sent with less than forward-secure encryption +func (p *packetPackerLegacy) 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 + var frames []wire.Frame + if p.version.UsesStopWaitingFrames() { // pack a STOP_WAITING first + swf := p.acks.GetStopWaitingFrame(true) + swf.PacketNumber = header.PacketNumber + swf.PacketNumberLen = header.PacketNumberLen + frames = append([]wire.Frame{swf}, packet.Frames...) + } else { + frames = packet.Frames + } + raw, err := p.writeAndSealPacket(header, frames, sealer) + return &packedPacket{ + header: header, + raw: raw, + frames: 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 *packetPackerLegacy) PackPacket() (*packedPacket, error) { + packet, err := p.maybePackCryptoPacket() + if err != nil { + return nil, err + } + 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) + headerLength, err := header.GetLength(p.version) + if err != nil { + return nil, err + } + + maxSize := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - headerLength + frames, err := p.composeNextPacket(header, maxSize, p.canSendData(encLevel)) + if err != nil { + return nil, err + } + + // Check if we have enough frames to send + if len(frames) == 0 { + return nil, nil + } + // check if this packet only contains an ACK (and maybe a STOP_WAITING) + if !ackhandler.HasRetransmittableFrames(frames) { + if p.numNonRetransmittableAcks >= protocol.MaxNonRetransmittableAcks { + frames = append(frames, &wire.PingFrame{}) + p.numNonRetransmittableAcks = 0 + } else { + p.numNonRetransmittableAcks++ + } + } else { + p.numNonRetransmittableAcks = 0 + } + + raw, err := p.writeAndSealPacket(header, frames, sealer) + if err != nil { + return nil, err + } + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, nil +} + +func (p *packetPackerLegacy) maybePackCryptoPacket() (*packedPacket, error) { + if !p.cryptoStream.hasData() { + return nil, nil + } + encLevel, sealer := p.cryptoSetup.GetSealerForCryptoStream() + header := p.getHeader(encLevel) + headerLength, err := header.GetLength(p.version) + if err != nil { + return nil, err + } + maxLen := p.maxPacketSize - protocol.ByteCount(sealer.Overhead()) - protocol.NonForwardSecurePacketSizeReduction - headerLength + sf, _ := p.cryptoStream.popStreamFrame(maxLen) + sf.DataLenPresent = false + frames := []wire.Frame{sf} + raw, err := p.writeAndSealPacket(header, frames, sealer) + if err != nil { + return nil, err + } + return &packedPacket{ + header: header, + raw: raw, + frames: frames, + encryptionLevel: encLevel, + }, nil +} + +func (p *packetPackerLegacy) composeNextPacket( + header *wire.Header, // only needed to fill in the STOP_WAITING frame + maxFrameSize protocol.ByteCount, + canSendStreamFrames bool, +) ([]wire.Frame, error) { + var length protocol.ByteCount + var frames []wire.Frame + + // STOP_WAITING and ACK will always fit + // ACKs need to go first, so that the sentPacketHandler will recognize them + if ack := p.acks.GetAckFrame(); ack != nil { + frames = append(frames, ack) + length += ack.Length(p.version) + // add a STOP_WAITING, for gQUIC + if p.version.UsesStopWaitingFrames() { + if swf := p.acks.GetStopWaitingFrame(false); swf != nil { + swf.PacketNumber = header.PacketNumber + swf.PacketNumberLen = header.PacketNumberLen + frames = append(frames, swf) + length += swf.Length(p.version) + } + } + } + + var lengthAdded protocol.ByteCount + 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 StreamFrames 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 + maxFrameSize += 2 + + frames = p.framer.AppendStreamFrames(frames, maxFrameSize-length) + if len(frames) > 0 { + lastFrame := frames[len(frames)-1] + if sf, ok := lastFrame.(*wire.StreamFrame); ok { + sf.DataLenPresent = false + } + } + return frames, nil +} + +func (p *packetPackerLegacy) getHeader(encLevel protocol.EncryptionLevel) *wire.Header { + pnum := p.packetNumberGenerator.Peek() + packetNumberLen := p.getPacketNumberLen(pnum) + + header := &wire.Header{ + PacketNumber: pnum, + PacketNumberLen: packetNumberLen, + Version: p.version, + } + + if p.version.UsesIETFHeaderFormat() && encLevel != protocol.EncryptionForwardSecure { + header.IsLongHeader = true + header.SrcConnectionID = p.srcConnID + header.PacketNumberLen = protocol.PacketNumberLen4 + if !p.hasSentPacket && p.perspective == protocol.PerspectiveClient { + header.Type = protocol.PacketTypeInitial + } else { + header.Type = protocol.PacketTypeHandshake + } + } + + if !p.omitConnectionID || encLevel != protocol.EncryptionForwardSecure { + header.DestConnectionID = p.destConnID + } + if p.perspective == protocol.PerspectiveServer && encLevel == protocol.EncryptionSecure { + header.Type = protocol.PacketType0RTT + header.DiversificationNonce = p.divNonce + } + if p.perspective == protocol.PerspectiveClient && encLevel != protocol.EncryptionForwardSecure { + header.VersionFlag = true + } + return header +} + +func (p *packetPackerLegacy) writeAndSealPacket( + header *wire.Header, + frames []wire.Frame, + sealer handshake.Sealer, +) ([]byte, error) { + raw := *getPacketBuffer() + buffer := bytes.NewBuffer(raw[:0]) + + if err := header.Write(buffer, p.perspective, p.version); err != nil { + return nil, err + } + payloadStartIndex := buffer.Len() + + for _, frame := range frames { + if err := frame.Write(buffer, p.version); err != nil { + return nil, err + } + } + + if size := protocol.ByteCount(buffer.Len() + sealer.Overhead()); size > p.maxPacketSize { + return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize) + } + + raw = raw[0:buffer.Len()] + _ = sealer.Seal(raw[payloadStartIndex:payloadStartIndex], raw[payloadStartIndex:], header.PacketNumber, raw[:payloadStartIndex]) + raw = raw[0 : buffer.Len()+sealer.Overhead()] + + num := p.packetNumberGenerator.Pop() + 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 *packetPackerLegacy) canSendData(encLevel protocol.EncryptionLevel) bool { + if p.perspective == protocol.PerspectiveClient { + return encLevel >= protocol.EncryptionSecure + } + return encLevel == protocol.EncryptionForwardSecure +} + +func (p *packetPackerLegacy) ChangeDestConnectionID(connID protocol.ConnectionID) { + panic("changing connection IDs not supported by gQUIC") +} + +func (p *packetPackerLegacy) HandleTransportParameters(params *handshake.TransportParameters) { + p.omitConnectionID = params.OmitConnectionID +} diff --git a/vendor/github.com/lucas-clemente/quic-go/receive_stream.go b/vendor/github.com/lucas-clemente/quic-go/receive_stream.go index 43c7bcf6..f07e6de3 100644 --- a/vendor/github.com/lucas-clemente/quic-go/receive_stream.go +++ b/vendor/github.com/lucas-clemente/quic-go/receive_stream.go @@ -8,6 +8,7 @@ import ( "github.com/lucas-clemente/quic-go/internal/flowcontrol" "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/internal/utils" "github.com/lucas-clemente/quic-go/internal/wire" ) @@ -43,8 +44,8 @@ type receiveStream struct { canceledRead bool // set when CancelRead() is called resetRemotely bool // set when HandleRstStreamFrame() is called - readChan chan struct{} - readDeadline time.Time + readChan chan struct{} + deadline time.Time flowController flowcontrol.StreamFlowController version protocol.VersionNumber @@ -108,6 +109,7 @@ func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, err return false, bytesRead, s.closeForShutdownErr } + var deadlineTimer *utils.Timer for { // Stop waiting on errors if s.closedForShutdown { @@ -120,9 +122,15 @@ func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, err return false, bytesRead, s.resetRemotelyErr } - deadline := s.readDeadline - if !deadline.IsZero() && !time.Now().Before(deadline) { - return false, bytesRead, errDeadline + deadline := s.deadline + if !deadline.IsZero() { + if !time.Now().Before(deadline) { + return false, bytesRead, errDeadline + } + if deadlineTimer == nil { + deadlineTimer = utils.NewTimer() + } + deadlineTimer.Reset(deadline) } if s.currentFrame != nil || s.currentFrameIsLast { @@ -135,7 +143,8 @@ func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, err } else { select { case <-s.readChan: - case <-time.After(time.Until(deadline)): + case <-deadlineTimer.Chan(): + deadlineTimer.SetRead() } } s.mutex.Lock() @@ -164,7 +173,9 @@ func (s *receiveStream) readImpl(p []byte) (bool /*stream completed */, int, err s.flowController.AddBytesRead(protocol.ByteCount(m)) } // increase the flow control window, if necessary - s.flowController.MaybeQueueWindowUpdate() + if s.streamID != s.version.CryptoStreamID() { + s.flowController.MaybeQueueWindowUpdate() + } if s.readPosInFrame >= len(s.currentFrame) && s.currentFrameIsLast { s.finRead = true @@ -270,13 +281,9 @@ func (s *receiveStream) onClose(offset protocol.ByteCount) { func (s *receiveStream) SetReadDeadline(t time.Time) error { s.mutex.Lock() - oldDeadline := s.readDeadline - s.readDeadline = t + s.deadline = t s.mutex.Unlock() - // if the new deadline is before the currently set deadline, wake up Read() - if t.Before(oldDeadline) { - s.signalRead() - } + s.signalRead() return nil } diff --git a/vendor/github.com/lucas-clemente/quic-go/send_stream.go b/vendor/github.com/lucas-clemente/quic-go/send_stream.go index eee66b6e..94bb83af 100644 --- a/vendor/github.com/lucas-clemente/quic-go/send_stream.go +++ b/vendor/github.com/lucas-clemente/quic-go/send_stream.go @@ -15,6 +15,7 @@ import ( type sendStreamI interface { SendStream handleStopSendingFrame(*wire.StopSendingFrame) + hasData() bool popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool) closeForShutdown(error) handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) @@ -40,8 +41,9 @@ type sendStream struct { finSent bool // set when a STREAM_FRAME with FIN bit has b dataForWriting []byte - writeChan chan struct{} - writeDeadline time.Time + + writeChan chan struct{} + deadline time.Time flowController flowcontrol.StreamFlowController @@ -85,49 +87,60 @@ func (s *sendStream) Write(p []byte) (int, error) { if s.closeForShutdownErr != nil { return 0, s.closeForShutdownErr } - if !s.writeDeadline.IsZero() && !time.Now().Before(s.writeDeadline) { + if !s.deadline.IsZero() && !time.Now().Before(s.deadline) { return 0, errDeadline } if len(p) == 0 { return 0, nil } - s.dataForWriting = make([]byte, len(p)) - copy(s.dataForWriting, p) - s.sender.onHasStreamData(s.streamID) + s.dataForWriting = p - var bytesWritten int - var err error + var ( + deadlineTimer *utils.Timer + bytesWritten int + notifiedSender bool + ) for { bytesWritten = len(p) - len(s.dataForWriting) - deadline := s.writeDeadline - if !deadline.IsZero() && !time.Now().Before(deadline) { - s.dataForWriting = nil - err = errDeadline - break + deadline := s.deadline + if !deadline.IsZero() { + if !time.Now().Before(deadline) { + s.dataForWriting = nil + return bytesWritten, errDeadline + } + if deadlineTimer == nil { + deadlineTimer = utils.NewTimer() + } + deadlineTimer.Reset(deadline) } if s.dataForWriting == nil || s.canceledWrite || s.closedForShutdown { break } s.mutex.Unlock() + if !notifiedSender { + s.sender.onHasStreamData(s.streamID) // must be called without holding the mutex + notifiedSender = true + } if deadline.IsZero() { <-s.writeChan } else { select { case <-s.writeChan: - case <-time.After(time.Until(deadline)): + case <-deadlineTimer.Chan(): + deadlineTimer.SetRead() } } s.mutex.Lock() } if s.closeForShutdownErr != nil { - err = s.closeForShutdownErr + return bytesWritten, s.closeForShutdownErr } else if s.cancelWriteErr != nil { - err = s.cancelWriteErr + return bytesWritten, s.cancelWriteErr } - return bytesWritten, err + return bytesWritten, nil } // popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream @@ -181,12 +194,18 @@ func (s *sendStream) popStreamFrameImpl(maxBytes protocol.ByteCount) (bool /* co return frame.FinBit, frame, s.dataForWriting != nil } +func (s *sendStream) hasData() bool { + s.mutex.Lock() + hasData := len(s.dataForWriting) > 0 + s.mutex.Unlock() + return hasData +} + func (s *sendStream) getDataForWriting(maxBytes protocol.ByteCount) ([]byte, bool /* should send FIN */) { if s.dataForWriting == nil { return nil, s.finishedWriting && !s.finSent } - // TODO(#657): Flow control for the crypto stream if s.streamID != s.version.CryptoStreamID() { maxBytes = utils.MinByteCount(maxBytes, s.flowController.SendWindowSize()) } @@ -196,10 +215,12 @@ func (s *sendStream) getDataForWriting(maxBytes protocol.ByteCount) ([]byte, boo var ret []byte if protocol.ByteCount(len(s.dataForWriting)) > maxBytes { - ret = s.dataForWriting[:maxBytes] + ret = make([]byte, int(maxBytes)) + copy(ret, s.dataForWriting[:maxBytes]) s.dataForWriting = s.dataForWriting[maxBytes:] } else { - ret = s.dataForWriting + ret = make([]byte, len(s.dataForWriting)) + copy(ret, s.dataForWriting) s.dataForWriting = nil s.signalWrite() } @@ -210,13 +231,14 @@ func (s *sendStream) getDataForWriting(maxBytes protocol.ByteCount) ([]byte, boo func (s *sendStream) Close() error { s.mutex.Lock() - defer s.mutex.Unlock() - if s.canceledWrite { + s.mutex.Unlock() return fmt.Errorf("Close called for canceled stream %d", s.streamID) } s.finishedWriting = true - s.sender.onHasStreamData(s.streamID) // need to send the FIN + s.mutex.Unlock() + + s.sender.onHasStreamData(s.streamID) // need to send the FIN, must be called without holding the mutex s.ctxCancel() return nil } @@ -227,7 +249,7 @@ func (s *sendStream) CancelWrite(errorCode protocol.ApplicationErrorCode) error s.mutex.Unlock() if completed { - s.sender.onStreamCompleted(s.streamID) + s.sender.onStreamCompleted(s.streamID) // must be called without holding the mutex } return err } @@ -260,12 +282,13 @@ func (s *sendStream) handleStopSendingFrame(frame *wire.StopSendingFrame) { } func (s *sendStream) handleMaxStreamDataFrame(frame *wire.MaxStreamDataFrame) { - s.flowController.UpdateSendWindow(frame.ByteOffset) s.mutex.Lock() - if s.dataForWriting != nil { + hasStreamData := s.dataForWriting != nil + s.mutex.Unlock() + s.flowController.UpdateSendWindow(frame.ByteOffset) + if hasStreamData { s.sender.onHasStreamData(s.streamID) } - s.mutex.Unlock() } // must be called after locking the mutex @@ -291,12 +314,9 @@ func (s *sendStream) Context() context.Context { func (s *sendStream) SetWriteDeadline(t time.Time) error { s.mutex.Lock() - oldDeadline := s.writeDeadline - s.writeDeadline = t + s.deadline = t s.mutex.Unlock() - if t.Before(oldDeadline) { - s.signalWrite() - } + s.signalWrite() return nil } diff --git a/vendor/github.com/lucas-clemente/quic-go/server.go b/vendor/github.com/lucas-clemente/quic-go/server.go index d9af6a43..3d370549 100644 --- a/vendor/github.com/lucas-clemente/quic-go/server.go +++ b/vendor/github.com/lucas-clemente/quic-go/server.go @@ -123,6 +123,9 @@ func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener, } func listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*server, error) { + if tlsConf == nil || (len(tlsConf.Certificates) == 0 && tlsConf.GetCertificate == nil) { + return nil, errors.New("quic: neither Certificates nor GetCertificate set in tls.Config") + } certChain := crypto.NewCertChain(tlsConf) kex, err := crypto.NewCurve25519KEX() if err != nil { diff --git a/vendor/github.com/lucas-clemente/quic-go/server_tls.go b/vendor/github.com/lucas-clemente/quic-go/server_tls.go index 01508df3..437bee2f 100644 --- a/vendor/github.com/lucas-clemente/quic-go/server_tls.go +++ b/vendor/github.com/lucas-clemente/quic-go/server_tls.go @@ -118,9 +118,6 @@ func (s *serverTLS) handleInitialImpl(p *receivedPacket) (quicSession, protocol. mconf := s.mintConf.Clone() mconf.ExtensionHandler = extHandler - // A server is allowed to perform multiple Retries. - // It doesn't make much sense, but it's something that our API allows. - // In that case it must use a source connection ID of at least 8 bytes. connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength) if err != nil { return nil, nil, err @@ -152,7 +149,7 @@ func (s *serverTLS) sendRetry(remoteAddr net.Addr, hdr *wire.Header) error { if err != nil { return err } - connID, err := protocol.GenerateConnectionIDForInitial() + connID, err := protocol.GenerateConnectionID(s.config.ConnectionIDLength) if err != nil { return err } diff --git a/vendor/github.com/lucas-clemente/quic-go/session.go b/vendor/github.com/lucas-clemente/quic-go/session.go index 81422d1f..0c33d2a0 100644 --- a/vendor/github.com/lucas-clemente/quic-go/session.go +++ b/vendor/github.com/lucas-clemente/quic-go/session.go @@ -92,12 +92,12 @@ type session struct { sentPacketHandler ackhandler.SentPacketHandler receivedPacketHandler ackhandler.ReceivedPacketHandler - streamFramer *streamFramer + framer *framer windowUpdateQueue *windowUpdateQueue connFlowController flowcontrol.ConnectionFlowController unpacker unpacker - packer *packetPacker + packer packer cryptoStreamHandler cryptoStreamHandler @@ -205,17 +205,17 @@ func newSession( s.cryptoStreamHandler = cs s.unpacker = newPacketUnpackerGQUIC(cs, s.version) s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective) - s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) - s.packer = newPacketPacker( + s.framer = newFramer(s.cryptoStream, s.streamsMap, s.version) + s.packer = newPacketPackerLegacy( destConnID, srcConnID, - 1, s.sentPacketHandler.GetPacketNumberLen, s.RemoteAddr(), - nil, // no token divNonce, + s.cryptoStream, cs, - s.streamFramer, + s.framer, + sentAndReceivedPacketManager{s.sentPacketHandler, s.receivedPacketHandler}, s.perspective, s.version, ) @@ -226,7 +226,6 @@ func newSession( var newClientSession = func( conn connection, sessionRunner sessionRunner, - hostname string, v protocol.VersionNumber, destConnID protocol.ConnectionID, srcConnID protocol.ConnectionID, @@ -261,7 +260,6 @@ var newClientSession = func( } cs, err := newCryptoSetupClient( s.cryptoStream, - hostname, destConnID, s.version, tlsConf, @@ -278,17 +276,17 @@ var newClientSession = func( s.cryptoStreamHandler = cs s.unpacker = newPacketUnpackerGQUIC(cs, s.version) s.streamsMap = newStreamsMapLegacy(s.newStream, s.config.MaxIncomingStreams, s.perspective) - s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) - s.packer = newPacketPacker( + s.framer = newFramer(s.cryptoStream, s.streamsMap, s.version) + s.packer = newPacketPackerLegacy( destConnID, srcConnID, - 1, s.sentPacketHandler.GetPacketNumberLen, s.RemoteAddr(), - nil, // no token nil, // no diversification nonce + s.cryptoStream, cs, - s.streamFramer, + s.framer, + sentAndReceivedPacketManager{s.sentPacketHandler, s.receivedPacketHandler}, s.perspective, s.version, ) @@ -333,7 +331,7 @@ func newTLSServerSession( } s.cryptoStreamHandler = cs s.streamsMap = newStreamsMap(s, s.newFlowController, s.config.MaxIncomingStreams, s.config.MaxIncomingUniStreams, s.perspective, s.version) - s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) + s.framer = newFramer(s.cryptoStream, s.streamsMap, s.version) s.packer = newPacketPacker( s.destConnID, s.srcConnID, @@ -341,9 +339,10 @@ func newTLSServerSession( s.sentPacketHandler.GetPacketNumberLen, s.RemoteAddr(), nil, // no token - nil, // no diversification nonce + s.cryptoStream, cs, - s.streamFramer, + s.framer, + sentAndReceivedPacketManager{s.sentPacketHandler, s.receivedPacketHandler}, s.perspective, s.version, ) @@ -397,7 +396,7 @@ var newTLSClientSession = func( s.cryptoStreamHandler = cs s.unpacker = newPacketUnpacker(cs, s.version) s.streamsMap = newStreamsMap(s, s.newFlowController, s.config.MaxIncomingStreams, s.config.MaxIncomingUniStreams, s.perspective, s.version) - s.streamFramer = newStreamFramer(s.cryptoStream, s.streamsMap, s.version) + s.framer = newFramer(s.cryptoStream, s.streamsMap, s.version) s.packer = newPacketPacker( s.destConnID, s.srcConnID, @@ -405,9 +404,10 @@ var newTLSClientSession = func( s.sentPacketHandler.GetPacketNumberLen, s.RemoteAddr(), token, - nil, // no diversification nonce + s.cryptoStream, cs, - s.streamFramer, + s.framer, + sentAndReceivedPacketManager{s.sentPacketHandler, s.receivedPacketHandler}, s.perspective, s.version, ) @@ -417,6 +417,7 @@ var newTLSClientSession = func( func (s *session) preSetup() { s.rttStats = &congestion.RTTStats{} s.sentPacketHandler = ackhandler.NewSentPacketHandler(s.rttStats, s.logger, s.version) + s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.rttStats, s.logger, s.version) s.connFlowController = flowcontrol.NewConnectionFlowController( protocol.ReceiveConnectionFlowControlWindow, protocol.ByteCount(s.config.MaxReceiveConnectionFlowControlWindow), @@ -439,8 +440,7 @@ func (s *session) postSetup() error { s.lastNetworkActivityTime = now s.sessionCreationTime = now - s.receivedPacketHandler = ackhandler.NewReceivedPacketHandler(s.rttStats, s.logger, s.version) - s.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.cryptoStream, s.connFlowController, s.packer.QueueControlFrame) + s.windowUpdateQueue = newWindowUpdateQueue(s.streamsMap, s.connFlowController, s.framer.QueueControlFrame) return nil } @@ -496,6 +496,7 @@ runLoop: putPacketBuffer(&p.header.Raw) case p := <-s.paramsChan: s.processTransportParameters(&p) + continue case _, ok := <-s.handshakeEvent: // when the handshake is completed, the channel will be closed s.handleHandshakeEvent(!ok) @@ -517,7 +518,7 @@ runLoop: if s.config.KeepAlive && !s.keepAlivePingSent && s.handshakeComplete && time.Since(s.lastNetworkActivityTime) >= s.peerParams.IdleTimeout/2 { // send a PING frame since there is no activity in the session s.logger.Debugf("Sending a keep-alive ping to keep the connection alive.") - s.packer.QueueControlFrame(&wire.PingFrame{}) + s.framer.QueueControlFrame(&wire.PingFrame{}) s.keepAlivePingSent = true } else if !pacingDeadline.IsZero() && now.Before(pacingDeadline) { // If we get to this point before the pacing deadline, we should wait until that deadline. @@ -527,18 +528,21 @@ runLoop: continue } - if err := s.sendPackets(); err != nil { - s.closeLocal(err) - } - if !s.receivedTooManyUndecrytablePacketsTime.IsZero() && s.receivedTooManyUndecrytablePacketsTime.Add(protocol.PublicResetTimeout).Before(now) && len(s.undecryptablePackets) != 0 { s.closeLocal(qerr.Error(qerr.DecryptionFailure, "too many undecryptable packets received")) + continue } if !s.handshakeComplete && now.Sub(s.sessionCreationTime) >= s.config.HandshakeTimeout { s.closeLocal(qerr.Error(qerr.HandshakeTimeout, "Crypto handshake did not complete in time.")) + continue } if s.handshakeComplete && now.Sub(s.lastNetworkActivityTime) >= s.config.IdleTimeout { s.closeLocal(qerr.Error(qerr.NetworkIdleTimeout, "No recent network activity.")) + continue + } + + if err := s.sendPackets(); err != nil { + s.closeLocal(err) } } @@ -906,12 +910,7 @@ func (s *session) handleCloseError(closeErr closeError) error { func (s *session) processTransportParameters(params *handshake.TransportParameters) { s.peerParams = params s.streamsMap.UpdateLimits(params) - if params.OmitConnectionID { - s.packer.SetOmitConnectionID() - } - if params.MaxPacketSize != 0 { - s.packer.SetMaxPacketSize(params.MaxPacketSize) - } + s.packer.HandleTransportParameters(params) s.connFlowController.UpdateSendWindow(params.ConnectionFlowControlWindow) // the crypto stream is the only open stream at this moment // so we don't need to update stream flow control windows @@ -933,6 +932,12 @@ sendLoop: case ackhandler.SendNone: break sendLoop case ackhandler.SendAck: + // If we already sent packets, and the send mode switches to SendAck, + // we've just become congestion limited. + // There's no need to try to send an ACK at this moment. + if numPacketsSent > 0 { + return nil + } // We can at most send a single ACK only packet. // There will only be a new ACK after receiving new packets. // SendAck is only returned when we're congestion limited, so we don't need to set the pacingt timer. @@ -978,21 +983,13 @@ sendLoop: } func (s *session) maybeSendAckOnlyPacket() error { - ack := s.receivedPacketHandler.GetAckFrame() - if ack == nil { - return nil - } - s.packer.QueueControlFrame(ack) - - if s.version.UsesStopWaitingFrames() { // for gQUIC, maybe add a STOP_WAITING - if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil { - s.packer.QueueControlFrame(swf) - } - } - packet, err := s.packer.PackAckPacket() + packet, err := s.packer.MaybePackAckPacket() if err != nil { return err } + if packet == nil { + return nil + } s.sentPacketHandler.SentPacket(packet.ToAckHandlerPacket()) return s.sendPackedPacket(packet) } @@ -1023,9 +1020,6 @@ func (s *session) maybeSendRetransmission() (bool, error) { s.logger.Debugf("Dequeueing retransmission for packet 0x%x", retransmitPacket.PacketNumber) } - if s.version.UsesStopWaitingFrames() { - s.packer.QueueControlFrame(s.sentPacketHandler.GetStopWaitingFrame(true)) - } packets, err := s.packer.PackRetransmission(retransmitPacket) if err != nil { return false, err @@ -1050,9 +1044,6 @@ func (s *session) sendProbePacket() error { } s.logger.Debugf("Sending a retransmission for %#x as a probe packet.", p.PacketNumber) - if s.version.UsesStopWaitingFrames() { - s.packer.QueueControlFrame(s.sentPacketHandler.GetStopWaitingFrame(true)) - } packets, err := s.packer.PackRetransmission(p) if err != nil { return err @@ -1072,19 +1063,10 @@ func (s *session) sendProbePacket() error { func (s *session) sendPacket() (bool, error) { if isBlocked, offset := s.connFlowController.IsNewlyBlocked(); isBlocked { - s.packer.QueueControlFrame(&wire.BlockedFrame{Offset: offset}) + s.framer.QueueControlFrame(&wire.BlockedFrame{Offset: offset}) } s.windowUpdateQueue.QueueAll() - if ack := s.receivedPacketHandler.GetAckFrame(); ack != nil { - s.packer.QueueControlFrame(ack) - if s.version.UsesStopWaitingFrames() { - if swf := s.sentPacketHandler.GetStopWaitingFrame(false); swf != nil { - s.packer.QueueControlFrame(swf) - } - } - } - packet, err := s.packer.PackPacket() if err != nil || packet == nil { return false, err @@ -1245,7 +1227,7 @@ func (s *session) tryDecryptingQueuedPackets() { } func (s *session) queueControlFrame(f wire.Frame) { - s.packer.QueueControlFrame(f) + s.framer.QueueControlFrame(f) s.scheduleSending() } @@ -1260,7 +1242,9 @@ func (s *session) onHasConnectionWindowUpdate() { } func (s *session) onHasStreamData(id protocol.StreamID) { - s.streamFramer.AddActiveStream(id) + if id != s.version.CryptoStreamID() { + s.framer.AddActiveStream(id) + } s.scheduleSending() } diff --git a/vendor/github.com/lucas-clemente/quic-go/stream.go b/vendor/github.com/lucas-clemente/quic-go/stream.go index 5d6ce671..64e4d46e 100644 --- a/vendor/github.com/lucas-clemente/quic-go/stream.go +++ b/vendor/github.com/lucas-clemente/quic-go/stream.go @@ -52,6 +52,7 @@ type streamI interface { handleRstStreamFrame(*wire.RstStreamFrame) error getWindowUpdate() protocol.ByteCount // for sending + hasData() bool handleStopSendingFrame(*wire.StopSendingFrame) popStreamFrame(maxBytes protocol.ByteCount) (*wire.StreamFrame, bool) handleMaxStreamDataFrame(*wire.MaxStreamDataFrame) diff --git a/vendor/github.com/lucas-clemente/quic-go/window_update_queue.go b/vendor/github.com/lucas-clemente/quic-go/window_update_queue.go index 6cd359e5..64b912a3 100644 --- a/vendor/github.com/lucas-clemente/quic-go/window_update_queue.go +++ b/vendor/github.com/lucas-clemente/quic-go/window_update_queue.go @@ -14,7 +14,6 @@ type windowUpdateQueue struct { queue map[protocol.StreamID]bool // used as a set queuedConn bool // connection-level window update - cryptoStream cryptoStream streamGetter streamGetter connFlowController flowcontrol.ConnectionFlowController callback func(wire.Frame) @@ -22,14 +21,12 @@ type windowUpdateQueue struct { func newWindowUpdateQueue( streamGetter streamGetter, - cryptoStream cryptoStream, connFC flowcontrol.ConnectionFlowController, cb func(wire.Frame), ) *windowUpdateQueue { return &windowUpdateQueue{ queue: make(map[protocol.StreamID]bool), streamGetter: streamGetter, - cryptoStream: cryptoStream, connFlowController: connFC, callback: cb, } @@ -55,17 +52,12 @@ func (q *windowUpdateQueue) QueueAll() { q.queuedConn = false } // queue all stream-level window updates - var offset protocol.ByteCount for id := range q.queue { - if id == q.cryptoStream.StreamID() { - offset = q.cryptoStream.getWindowUpdate() - } else { - str, err := q.streamGetter.GetOrOpenReceiveStream(id) - if err != nil || str == nil { // the stream can be nil if it was completed before dequeing the window update - continue - } - offset = str.getWindowUpdate() + str, err := q.streamGetter.GetOrOpenReceiveStream(id) + if err != nil || str == nil { // the stream can be nil if it was completed before dequeing the window update + continue } + offset := str.getWindowUpdate() if offset == 0 { // can happen if we received a final offset, right after queueing the window update continue } diff --git a/vendor/manifest b/vendor/manifest index 71afc830..32208377 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -130,7 +130,7 @@ "importpath": "github.com/lucas-clemente/quic-go", "repository": "https://github.com/lucas-clemente/quic-go", "vcs": "git", - "revision": "71635f6961ad00ca5c088be625624e4a2cd1c066", + "revision": "f90751eabaa39364e3861ee5a8b179f140847d7e", "branch": "HEAD", "notests": true },