diff --git a/go.mod b/go.mod index 97c55a1e80..8953671081 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/miekg/dns v1.1.64 github.com/opencoff/go-sieve v0.2.1 github.com/powerman/check v1.8.0 - github.com/quic-go/quic-go v0.50.1 + github.com/quic-go/quic-go v0.51.0 golang.org/x/crypto v0.36.0 golang.org/x/net v0.38.0 golang.org/x/sys v0.31.0 @@ -42,7 +42,6 @@ require ( github.com/quic-go/qpack v0.5.1 // indirect github.com/smartystreets/goconvey v1.8.1 // indirect go.uber.org/mock v0.5.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/mod v0.23.0 // indirect golang.org/x/sync v0.12.0 // indirect golang.org/x/text v0.23.0 // indirect diff --git a/go.sum b/go.sum index 655a71c0e5..c47ab4df2a 100644 --- a/go.sum +++ b/go.sum @@ -75,8 +75,8 @@ github.com/powerman/deepequal v0.1.0 h1:sVwtyTsBuYIvdbLR1O2wzRY63YgPqdGZmk/o80l+ github.com/powerman/deepequal v0.1.0/go.mod h1:3k7aG/slufBhUANdN67o/UPg8i5YaiJ6FmibWX0cn04= github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= -github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= -github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= +github.com/quic-go/quic-go v0.51.0 h1:K8exxe9zXxeRKxaXxi/GpUqYiTrtdiWP8bo1KFya6Wc= +github.com/quic-go/quic-go v0.51.0/go.mod h1:MFlGGpcpJqRAfmYi6NC2cptDPSxRWTOGNuP4wqrWmzQ= github.com/smarty/assertions v1.15.0 h1:cR//PqUBUiQRakZWqBiFFQ9wb8emQGDb0HeGdqGByCY= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sSznIX1xY= @@ -89,8 +89,6 @@ go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= @@ -104,8 +102,6 @@ golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/vendor/github.com/quic-go/quic-go/.golangci.yml b/vendor/github.com/quic-go/quic-go/.golangci.yml index 1174b125e1..656fa76dd6 100644 --- a/vendor/github.com/quic-go/quic-go/.golangci.yml +++ b/vendor/github.com/quic-go/quic-go/.golangci.yml @@ -1,51 +1,85 @@ -linters-settings: - misspell: - ignore-words: - - ect - depguard: - rules: - quicvarint: - list-mode: strict - files: - - "**/github.com/quic-go/quic-go/quicvarint/*" - - "!$test" - allow: - - $gostd - +version: "2" linters: - disable-all: true + default: none enable: - asciicheck - copyloopvar - depguard - exhaustive - - goimports - - gofmt # redundant, since gofmt *should* be a no-op after gofumpt - - gofumpt - - gosimple - govet - ineffassign - misspell - prealloc - staticcheck - - stylecheck - unconvert - unparam - unused - -issues: - exclude-files: - - internal/handshake/cipher_suite.go - exclude-rules: - - path: internal/qtls - linters: - - depguard - - path: _test\.go - linters: - - exhaustive - - prealloc - - unparam - - path: _test\.go - text: "SA1029:" - linters: - - staticcheck + settings: + depguard: + rules: + random: + deny: + - pkg: "math/rand$" + desc: use math/rand/v2 + - pkg: "golang.org/x/exp/rand" + desc: use math/rand/v2 + quicvarint: + list-mode: strict + files: + - '**/github.com/quic-go/quic-go/quicvarint/*' + - '!$test' + allow: + - $gostd + rsa: + list-mode: original + deny: + - pkg: crypto/rsa + desc: "use crypto/ed25519 instead" + misspell: + ignore-rules: + - ect + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - depguard + path: internal/qtls + - linters: + - exhaustive + - prealloc + - unparam + path: _test\.go + - linters: + - staticcheck + path: _test\.go + text: 'SA1029:' # inappropriate key in call to context.WithValue + # WebTransport still relies on the ConnectionTracingID and ConnectionTracingKey. + # See https://github.com/quic-go/quic-go/issues/4405 for more details. + - linters: + - staticcheck + paths: + - http3/ + - integrationtests/self/http_test.go + text: 'SA1019:.+quic\.ConnectionTracing(ID|Key)' + paths: + - internal/handshake/cipher_suite.go + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gofmt + - gofumpt + - goimports + exclusions: + generated: lax + paths: + - internal/handshake/cipher_suite.go + - third_party$ + - builtin$ + - examples$ diff --git a/vendor/github.com/quic-go/quic-go/client.go b/vendor/github.com/quic-go/quic-go/client.go index 29a715cc6d..26cd835845 100644 --- a/vendor/github.com/quic-go/quic-go/client.go +++ b/vendor/github.com/quic-go/quic-go/client.go @@ -15,7 +15,7 @@ var generateConnectionIDForInitial = protocol.GenerateConnectionIDForInitial // DialAddr establishes a new QUIC connection to a server. // It resolves the address, and then creates a new UDP connection to dial the QUIC server. // When the QUIC connection is closed, this UDP connection is closed. -// See Dial for more details. +// See [Dial] for more details. func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (Connection, error) { udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) if err != nil { @@ -33,7 +33,7 @@ func DialAddr(ctx context.Context, addr string, tlsConf *tls.Config, conf *Confi } // DialAddrEarly establishes a new 0-RTT QUIC connection to a server. -// See DialAddr for more details. +// See [DialAddr] for more details. func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { udpConn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) if err != nil { @@ -56,7 +56,7 @@ func DialAddrEarly(ctx context.Context, addr string, tlsConf *tls.Config, conf * } // DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn. -// See Dial for more details. +// See [Dial] for more details. func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (EarlyConnection, error) { dl, err := setupTransport(c, tlsConf, false) if err != nil { @@ -71,12 +71,12 @@ func DialEarly(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tl } // Dial establishes a new QUIC connection to a server using a net.PacketConn. -// If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does), +// If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does), // ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP // will be used instead of ReadFrom and WriteTo to read/write packets. // The tls.Config must define an application protocol (using NextProtos). // -// This is a convenience function. More advanced use cases should instantiate a Transport, +// This is a convenience function. More advanced use cases should instantiate a [Transport], // which offers configuration options for a more fine-grained control of the connection establishment, // including reusing the underlying UDP socket for multiple QUIC connections. func Dial(ctx context.Context, c net.PacketConn, addr net.Addr, tlsConf *tls.Config, conf *Config) (Connection, error) { diff --git a/vendor/github.com/quic-go/quic-go/config.go b/vendor/github.com/quic-go/quic-go/config.go index d42bdc1c5f..540a3240bc 100644 --- a/vendor/github.com/quic-go/quic-go/config.go +++ b/vendor/github.com/quic-go/quic-go/config.go @@ -8,7 +8,7 @@ import ( "github.com/quic-go/quic-go/quicvarint" ) -// Clone clones a Config +// Clone clones a Config. func (c *Config) Clone() *Config { copy := *c return © diff --git a/vendor/github.com/quic-go/quic-go/conn_id_generator.go b/vendor/github.com/quic-go/quic-go/conn_id_generator.go index c309c2cd75..e05fbd7fb4 100644 --- a/vendor/github.com/quic-go/quic-go/conn_id_generator.go +++ b/vendor/github.com/quic-go/quic-go/conn_id_generator.go @@ -8,41 +8,67 @@ import ( "github.com/quic-go/quic-go/internal/wire" ) +type connRunnerCallbacks struct { + AddConnectionID func(protocol.ConnectionID) + RemoveConnectionID func(protocol.ConnectionID) + RetireConnectionID func(protocol.ConnectionID) + ReplaceWithClosed func([]protocol.ConnectionID, []byte) +} + +type connRunners map[transportID]connRunnerCallbacks + +func (cr connRunners) AddConnectionID(id protocol.ConnectionID) { + for _, c := range cr { + c.AddConnectionID(id) + } +} + +func (cr connRunners) RemoveConnectionID(id protocol.ConnectionID) { + for _, c := range cr { + c.RemoveConnectionID(id) + } +} + +func (cr connRunners) RetireConnectionID(id protocol.ConnectionID) { + for _, c := range cr { + c.RetireConnectionID(id) + } +} + +func (cr connRunners) ReplaceWithClosed(ids []protocol.ConnectionID, b []byte) { + for _, c := range cr { + c.ReplaceWithClosed(ids, b) + } +} + type connIDGenerator struct { - generator ConnectionIDGenerator - highestSeq uint64 + generator ConnectionIDGenerator + highestSeq uint64 + connRunners connRunners activeSrcConnIDs map[uint64]protocol.ConnectionID initialClientDestConnID *protocol.ConnectionID // nil for the client - addConnectionID func(protocol.ConnectionID) - statelessResetter *statelessResetter - removeConnectionID func(protocol.ConnectionID) - retireConnectionID func(protocol.ConnectionID) - replaceWithClosed func([]protocol.ConnectionID, []byte) - queueControlFrame func(wire.Frame) + statelessResetter *statelessResetter + + queueControlFrame func(wire.Frame) } func newConnIDGenerator( + tID transportID, initialConnectionID protocol.ConnectionID, initialClientDestConnID *protocol.ConnectionID, // nil for the client - addConnectionID func(protocol.ConnectionID), statelessResetter *statelessResetter, - removeConnectionID func(protocol.ConnectionID), - retireConnectionID func(protocol.ConnectionID), - replaceWithClosed func([]protocol.ConnectionID, []byte), + connRunner connRunnerCallbacks, queueControlFrame func(wire.Frame), generator ConnectionIDGenerator, ) *connIDGenerator { m := &connIDGenerator{ - generator: generator, - activeSrcConnIDs: make(map[uint64]protocol.ConnectionID), - addConnectionID: addConnectionID, - statelessResetter: statelessResetter, - removeConnectionID: removeConnectionID, - retireConnectionID: retireConnectionID, - replaceWithClosed: replaceWithClosed, - queueControlFrame: queueControlFrame, + generator: generator, + activeSrcConnIDs: make(map[uint64]protocol.ConnectionID), + statelessResetter: statelessResetter, + connRunners: map[transportID]connRunnerCallbacks{tID: connRunner}, + queueControlFrame: queueControlFrame, } m.activeSrcConnIDs[0] = initialConnectionID m.initialClientDestConnID = initialClientDestConnID @@ -85,7 +111,7 @@ func (m *connIDGenerator) Retire(seq uint64, sentWithDestConnID protocol.Connect ErrorMessage: fmt.Sprintf("retired connection ID %d (%s), which was used as the Destination Connection ID on this packet", seq, connID), } } - m.retireConnectionID(connID) + m.connRunners.RetireConnectionID(connID) delete(m.activeSrcConnIDs, seq) // Don't issue a replacement for the initial connection ID. if seq == 0 { @@ -100,7 +126,7 @@ func (m *connIDGenerator) issueNewConnID() error { return err } m.activeSrcConnIDs[m.highestSeq+1] = connID - m.addConnectionID(connID) + m.connRunners.AddConnectionID(connID) m.queueControlFrame(&wire.NewConnectionIDFrame{ SequenceNumber: m.highestSeq + 1, ConnectionID: connID, @@ -112,17 +138,17 @@ func (m *connIDGenerator) issueNewConnID() error { func (m *connIDGenerator) SetHandshakeComplete() { if m.initialClientDestConnID != nil { - m.retireConnectionID(*m.initialClientDestConnID) + m.connRunners.RetireConnectionID(*m.initialClientDestConnID) m.initialClientDestConnID = nil } } func (m *connIDGenerator) RemoveAll() { if m.initialClientDestConnID != nil { - m.removeConnectionID(*m.initialClientDestConnID) + m.connRunners.RemoveConnectionID(*m.initialClientDestConnID) } for _, connID := range m.activeSrcConnIDs { - m.removeConnectionID(connID) + m.connRunners.RemoveConnectionID(connID) } } @@ -134,5 +160,20 @@ func (m *connIDGenerator) ReplaceWithClosed(connClose []byte) { for _, connID := range m.activeSrcConnIDs { connIDs = append(connIDs, connID) } - m.replaceWithClosed(connIDs, connClose) + m.connRunners.ReplaceWithClosed(connIDs, connClose) +} + +func (m *connIDGenerator) AddConnRunner(id transportID, r connRunnerCallbacks) { + // The transport might have already been added earlier. + // This happens if the application migrates back to and old path. + if _, ok := m.connRunners[id]; ok { + return + } + m.connRunners[id] = r + if m.initialClientDestConnID != nil { + r.AddConnectionID(*m.initialClientDestConnID) + } + for _, connID := range m.activeSrcConnIDs { + r.AddConnectionID(connID) + } } diff --git a/vendor/github.com/quic-go/quic-go/conn_id_manager.go b/vendor/github.com/quic-go/quic-go/conn_id_manager.go index a4fbd93cd2..5513b645d9 100644 --- a/vendor/github.com/quic-go/quic-go/conn_id_manager.go +++ b/vendor/github.com/quic-go/quic-go/conn_id_manager.go @@ -2,11 +2,11 @@ package quic import ( "fmt" + "slices" "github.com/quic-go/quic-go/internal/protocol" "github.com/quic-go/quic-go/internal/qerr" "github.com/quic-go/quic-go/internal/utils" - list "github.com/quic-go/quic-go/internal/utils/linkedlist" "github.com/quic-go/quic-go/internal/wire" ) @@ -17,7 +17,7 @@ type newConnID struct { } type connIDManager struct { - queue list.List[newConnID] + queue []newConnID highestProbingID uint64 pathProbing map[pathID]newConnID // initialized lazily @@ -53,6 +53,7 @@ func newConnIDManager( addStatelessResetToken: addStatelessResetToken, removeStatelessResetToken: removeStatelessResetToken, queueControlFrame: queueControlFrame, + queue: make([]newConnID, 0, protocol.MaxActiveConnectionIDs), } } @@ -64,7 +65,7 @@ func (h *connIDManager) Add(f *wire.NewConnectionIDFrame) error { if err := h.add(f); err != nil { return err } - if h.queue.Len() >= protocol.MaxActiveConnectionIDs { + if len(h.queue) >= protocol.MaxActiveConnectionIDs { return &qerr.TransportError{ErrorCode: qerr.ConnectionIDLimitError} } return nil @@ -92,6 +93,7 @@ func (h *connIDManager) add(f *wire.NewConnectionIDFrame) error { h.queueControlFrame(&wire.RetireConnectionIDFrame{ SequenceNumber: entry.SequenceNumber, }) + h.removeStatelessResetToken(entry.StatelessResetToken) delete(h.pathProbing, id) } } @@ -99,17 +101,15 @@ func (h *connIDManager) add(f *wire.NewConnectionIDFrame) error { // Retire elements in the queue. // Doesn't retire the active connection ID. if f.RetirePriorTo > h.highestRetired { - var next *list.Element[newConnID] - for el := h.queue.Front(); el != nil; el = next { - if el.Value.SequenceNumber >= f.RetirePriorTo { - break + var newQueue []newConnID + for _, entry := range h.queue { + if entry.SequenceNumber >= f.RetirePriorTo { + newQueue = append(newQueue, entry) + } else { + h.queueControlFrame(&wire.RetireConnectionIDFrame{SequenceNumber: entry.SequenceNumber}) } - next = el.Next() - h.queueControlFrame(&wire.RetireConnectionIDFrame{ - SequenceNumber: el.Value.SequenceNumber, - }) - h.queue.Remove(el) } + h.queue = newQueue h.highestRetired = f.RetirePriorTo } @@ -130,36 +130,39 @@ func (h *connIDManager) add(f *wire.NewConnectionIDFrame) error { } func (h *connIDManager) addConnectionID(seq uint64, connID protocol.ConnectionID, resetToken protocol.StatelessResetToken) error { - // insert a new element at the end - if h.queue.Len() == 0 || h.queue.Back().Value.SequenceNumber < seq { - h.queue.PushBack(newConnID{ + // fast path: add to the end of the queue + if len(h.queue) == 0 || h.queue[len(h.queue)-1].SequenceNumber < seq { + h.queue = append(h.queue, newConnID{ SequenceNumber: seq, ConnectionID: connID, StatelessResetToken: resetToken, }) return nil } - // insert a new element somewhere in the middle - for el := h.queue.Front(); el != nil; el = el.Next() { - if el.Value.SequenceNumber == seq { - if el.Value.ConnectionID != connID { + + // slow path: insert in the middle + for i, entry := range h.queue { + if entry.SequenceNumber == seq { + if entry.ConnectionID != connID { return fmt.Errorf("received conflicting connection IDs for sequence number %d", seq) } - if el.Value.StatelessResetToken != resetToken { + if entry.StatelessResetToken != resetToken { return fmt.Errorf("received conflicting stateless reset tokens for sequence number %d", seq) } - break + return nil } - if el.Value.SequenceNumber > seq { - h.queue.InsertBefore(newConnID{ + + // insert at the correct position to maintain sorted order + if entry.SequenceNumber > seq { + h.queue = slices.Insert(h.queue, i, newConnID{ SequenceNumber: seq, ConnectionID: connID, StatelessResetToken: resetToken, - }, el) - break + }) + return nil } } - return nil + return nil // unreachable } func (h *connIDManager) updateConnectionID() { @@ -172,7 +175,8 @@ func (h *connIDManager) updateConnectionID() { h.removeStatelessResetToken(*h.activeStatelessResetToken) } - front := h.queue.Remove(h.queue.Front()) + front := h.queue[0] + h.queue = h.queue[1:] h.activeSequenceNumber = front.SequenceNumber h.activeConnectionID = front.ConnectionID h.activeStatelessResetToken = &front.StatelessResetToken @@ -186,6 +190,11 @@ func (h *connIDManager) Close() { if h.activeStatelessResetToken != nil { h.removeStatelessResetToken(*h.activeStatelessResetToken) } + if h.pathProbing != nil { + for _, entry := range h.pathProbing { + h.removeStatelessResetToken(entry.StatelessResetToken) + } + } } // is called when the server performs a Retry @@ -216,13 +225,13 @@ func (h *connIDManager) shouldUpdateConnID() bool { return false } // initiate the first change as early as possible (after handshake completion) - if h.queue.Len() > 0 && h.activeSequenceNumber == 0 { + if len(h.queue) > 0 && h.activeSequenceNumber == 0 { return true } // For later changes, only change if // 1. The queue of connection IDs is filled more than 50%. // 2. We sent at least PacketsPerConnectionID packets - return 2*h.queue.Len() >= protocol.MaxActiveConnectionIDs && + return 2*len(h.queue) >= protocol.MaxActiveConnectionIDs && h.packetsSinceLastChange >= h.packetsPerConnectionID } @@ -256,12 +265,14 @@ func (h *connIDManager) GetConnIDForPath(id pathID) (protocol.ConnectionID, bool if ok { return entry.ConnectionID, true } - if h.queue.Len() == 0 { + if len(h.queue) == 0 { return protocol.ConnectionID{}, false } - front := h.queue.Remove(h.queue.Front()) + front := h.queue[0] + h.queue = h.queue[1:] h.pathProbing[id] = front h.highestProbingID = front.SequenceNumber + h.addStatelessResetToken(front.StatelessResetToken) return front.ConnectionID, true } @@ -279,9 +290,26 @@ func (h *connIDManager) RetireConnIDForPath(pathID pathID) { h.queueControlFrame(&wire.RetireConnectionIDFrame{ SequenceNumber: entry.SequenceNumber, }) + h.removeStatelessResetToken(entry.StatelessResetToken) delete(h.pathProbing, pathID) } +func (h *connIDManager) IsActiveStatelessResetToken(token protocol.StatelessResetToken) bool { + if h.activeStatelessResetToken != nil { + if *h.activeStatelessResetToken == token { + return true + } + } + if h.pathProbing != nil { + for _, entry := range h.pathProbing { + if entry.StatelessResetToken == token { + return true + } + } + } + return false +} + // Using the connIDManager after it has been closed can have disastrous effects: // If the connection ID is rotated, a new entry would be inserted into the packet handler map, // leading to a memory leak of the connection struct. diff --git a/vendor/github.com/quic-go/quic-go/connection.go b/vendor/github.com/quic-go/quic-go/connection.go index 9415584de5..5555cfd1ef 100644 --- a/vendor/github.com/quic-go/quic-go/connection.go +++ b/vendor/github.com/quic-go/quic-go/connection.go @@ -112,6 +112,8 @@ func nextConnTracingID() ConnectionTracingID { return ConnectionTracingID(connTr // A Connection is a QUIC connection type connection struct { + tr *Transport + // Destination connection ID used during the handshake. // Used to check source connection ID on incoming packets. handshakeDestConnID protocol.ConnectionID @@ -129,8 +131,9 @@ type connection struct { sendQueue sender // lazily initialzed: most connections never migrate - pathManager *pathManager - largestRcvdAppData protocol.PacketNumber + pathManager *pathManager + largestRcvdAppData protocol.PacketNumber + pathManagerOutgoing atomic.Pointer[pathManagerOutgoing] streamsMap streamManager connIDManager *connIDManager @@ -223,7 +226,7 @@ var newConnection = func( ctx context.Context, ctxCancel context.CancelCauseFunc, conn sendConn, - runner connRunner, + tr *Transport, origDestConnID protocol.ConnectionID, retrySrcConnID *protocol.ConnectionID, clientDestConnID protocol.ConnectionID, @@ -242,6 +245,7 @@ var newConnection = func( s := &connection{ ctx: ctx, ctxCancel: ctxCancel, + tr: tr, conn: conn, config: conf, handshakeDestConnID: destConnID, @@ -258,6 +262,7 @@ var newConnection = func( } else { s.logID = destConnID.String() } + runner := tr.connRunner() s.connIDManager = newConnIDManager( destConnID, func(token protocol.StatelessResetToken) { runner.AddResetToken(token, s) }, @@ -265,13 +270,16 @@ var newConnection = func( s.queueControlFrame, ) s.connIDGenerator = newConnIDGenerator( + tr.id(), srcConnID, &clientDestConnID, - func(connID protocol.ConnectionID) { runner.Add(connID, s) }, statelessResetter, - runner.Remove, - runner.Retire, - runner.ReplaceWithClosed, + connRunnerCallbacks{ + AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, s) }, + RemoveConnectionID: runner.Remove, + RetireConnectionID: runner.Retire, + ReplaceWithClosed: runner.ReplaceWithClosed, + }, s.queueControlFrame, connIDGenerator, ) @@ -299,7 +307,6 @@ var newConnection = func( MaxAckDelay: protocol.MaxAckDelayInclGranularity, AckDelayExponent: protocol.AckDelayExponent, MaxUDPPayloadSize: protocol.MaxPacketBufferSize, - DisableActiveMigration: true, StatelessResetToken: &statelessResetToken, OriginalDestinationConnectionID: origDestConnID, // For interoperability with quic-go versions before May 2023, this value must be set to a value @@ -342,7 +349,7 @@ var newConnection = func( var newClientConnection = func( ctx context.Context, conn sendConn, - runner connRunner, + tr *Transport, destConnID protocol.ConnectionID, srcConnID protocol.ConnectionID, connIDGenerator ConnectionIDGenerator, @@ -357,6 +364,7 @@ var newClientConnection = func( v protocol.Version, ) quicConn { s := &connection{ + tr: tr, conn: conn, config: conf, origDestConnID: destConnID, @@ -369,6 +377,7 @@ var newClientConnection = func( versionNegotiated: hasNegotiatedVersion, version: v, } + runner := tr.connRunner() s.connIDManager = newConnIDManager( destConnID, func(token protocol.StatelessResetToken) { runner.AddResetToken(token, s) }, @@ -376,13 +385,16 @@ var newClientConnection = func( s.queueControlFrame, ) s.connIDGenerator = newConnIDGenerator( + tr.id(), srcConnID, nil, - func(connID protocol.ConnectionID) { runner.Add(connID, s) }, statelessResetter, - runner.Remove, - runner.Retire, - runner.ReplaceWithClosed, + connRunnerCallbacks{ + AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, s) }, + RemoveConnectionID: runner.Remove, + RetireConnectionID: runner.Retire, + ReplaceWithClosed: runner.ReplaceWithClosed, + }, s.queueControlFrame, connIDGenerator, ) @@ -411,7 +423,6 @@ var newClientConnection = func( MaxAckDelay: protocol.MaxAckDelayInclGranularity, MaxUDPPayloadSize: protocol.MaxPacketBufferSize, AckDelayExponent: protocol.AckDelayExponent, - DisableActiveMigration: true, // For interoperability with quic-go versions before May 2023, this value must be set to a value // different from protocol.DefaultActiveConnectionIDLimit. // If set to the default value, it will be omitted from the transport parameters, which will make @@ -586,7 +597,7 @@ runLoop: // We don't need to wait for new events if: // * we processed packets: we probably need to send an ACK, and potentially more data // * the pacer allows us to send more packets immediately - shouldProceedImmediately := sendQueueAvailable == nil && (processed || s.pacingDeadline == deadlineSendImmediately) + shouldProceedImmediately := sendQueueAvailable == nil && (processed || s.pacingDeadline.Equal(deadlineSendImmediately)) if !shouldProceedImmediately { // 3rd: wait for something to happen: // * closing of the connection @@ -641,6 +652,16 @@ runLoop: } } + if s.perspective == protocol.PerspectiveClient { + pm := s.pathManagerOutgoing.Load() + if pm != nil { + tr, ok := pm.ShouldSwitchPath() + if ok { + s.switchToNewPath(tr, now) + } + } + } + if s.sendQueue.WouldBlock() { // The send queue is still busy sending out packets. Wait until there's space to enqueue new packets. sendQueueAvailable = s.sendQueue.Available() @@ -755,6 +776,24 @@ func (s *connection) idleTimeoutStartTime() time.Time { return startTime } +func (s *connection) switchToNewPath(tr *Transport, now time.Time) { + initialPacketSize := protocol.ByteCount(s.config.InitialPacketSize) + s.sentPacketHandler.MigratedPath(now, initialPacketSize) + maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize) + if s.peerParams.MaxUDPPayloadSize > 0 && s.peerParams.MaxUDPPayloadSize < maxPacketSize { + maxPacketSize = s.peerParams.MaxUDPPayloadSize + } + s.mtuDiscoverer.Reset(now, initialPacketSize, maxPacketSize) + s.conn = newSendConn(tr.conn, s.conn.RemoteAddr(), packetInfo{}, utils.DefaultLogger) // TODO: find a better way + s.sendQueue.Close() + s.sendQueue = newSendQueue(s.conn) + go func() { + if err := s.sendQueue.Run(); err != nil { + s.destroyImpl(err) + } + }() +} + func (s *connection) handleHandshakeComplete(now time.Time) error { defer close(s.handshakeCompleteChan) // Once the handshake completes, we have derived 1-RTT keys. @@ -938,7 +977,7 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er if counter > 0 { p.buffer.Split() } - processed, err := s.handleShortHeaderPacket(p) + processed, err := s.handleShortHeaderPacket(p, counter > 0) if err != nil { return false, err } @@ -953,7 +992,7 @@ func (s *connection) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ er return wasProcessed, nil } -func (s *connection) handleShortHeaderPacket(p receivedPacket) (wasProcessed bool, _ error) { +func (s *connection) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasProcessed bool, _ error) { var wasQueued bool defer func() { @@ -970,6 +1009,17 @@ func (s *connection) handleShortHeaderPacket(p receivedPacket) (wasProcessed boo } pn, pnLen, keyPhase, data, err := s.unpacker.UnpackShortHeader(p.rcvTime, p.data) if err != nil { + // Stateless reset packets (see RFC 9000, section 10.3): + // * fill the entire UDP datagram (i.e. they cannot be part of a coalesced packet) + // * are short header packets (first bit is 0) + // * have the QUIC bit set (second bit is 1) + // * are at least 21 bytes long + if !isCoalesced && len(p.data) >= protocol.MinReceivedStatelessResetSize && p.data[0]&0b11000000 == 0b01000000 { + token := protocol.StatelessResetToken(p.data[len(p.data)-16:]) + if s.connIDManager.IsActiveStatelessResetToken(token) { + return false, &StatelessResetError{} + } + } wasQueued, err = s.handleUnpackError(err, p, logging.PacketType1RTT) return false, err } @@ -1004,7 +1054,7 @@ func (s *connection) handleShortHeaderPacket(p receivedPacket) (wasProcessed boo ) } } - isNonProbing, err := s.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log) + isNonProbing, pathChallenge, err := s.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log) if err != nil { return false, err } @@ -1013,45 +1063,46 @@ func (s *connection) handleShortHeaderPacket(p receivedPacket) (wasProcessed boo if s.perspective == protocol.PerspectiveClient { return true, nil } + if addrsEqual(p.remoteAddr, s.RemoteAddr()) { + return true, nil + } var shouldSwitchPath bool - if pn == s.largestRcvdAppData && !addrsEqual(p.remoteAddr, s.RemoteAddr()) { - if s.pathManager == nil { - s.pathManager = newPathManager( - s.connIDManager.GetConnIDForPath, - s.connIDManager.RetireConnIDForPath, - s.logger, - ) - } - var destConnID protocol.ConnectionID - var pathChallenge ackhandler.Frame - destConnID, pathChallenge, shouldSwitchPath = s.pathManager.HandlePacket(p, isNonProbing) - if pathChallenge.Frame != nil { - probe, buf, err := s.packer.PackPathProbePacket(destConnID, pathChallenge, s.version) - if err != nil { - return false, err - } - s.logger.Debugf("sending path probe packet to %s", p.remoteAddr) - s.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) - s.registerPackedShortHeaderPacket(probe, protocol.ECNNon, p.rcvTime) - s.sendQueue.SendProbe(buf, p.remoteAddr) - } + if s.pathManager == nil { + s.pathManager = newPathManager( + s.connIDManager.GetConnIDForPath, + s.connIDManager.RetireConnIDForPath, + s.logger, + ) } - - if shouldSwitchPath { - s.pathManager.SwitchToPath(p.remoteAddr) - s.sentPacketHandler.MigratedPath(p.rcvTime, protocol.ByteCount(s.config.InitialPacketSize)) - maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize) - if s.peerParams.MaxUDPPayloadSize > 0 && s.peerParams.MaxUDPPayloadSize < maxPacketSize { - maxPacketSize = s.peerParams.MaxUDPPayloadSize + destConnID, frames, shouldSwitchPath := s.pathManager.HandlePacket(p.remoteAddr, p.rcvTime, pathChallenge, isNonProbing) + if len(frames) > 0 { + probe, buf, err := s.packer.PackPathProbePacket(destConnID, frames, s.version) + if err != nil { + return true, err } - s.mtuDiscoverer.Reset( - p.rcvTime, - protocol.ByteCount(s.config.InitialPacketSize), - maxPacketSize, - ) - s.conn.ChangeRemoteAddr(p.remoteAddr, p.info) + s.logger.Debugf("sending path probe packet to %s", p.remoteAddr) + s.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) + s.registerPackedShortHeaderPacket(probe, protocol.ECNNon, p.rcvTime) + s.sendQueue.SendProbe(buf, p.remoteAddr) + } + // We only switch paths in response to the highest-numbered non-probing packet, + // see section 9.3 of RFC 9000. + if !shouldSwitchPath || pn != s.largestRcvdAppData { + return true, nil } + s.pathManager.SwitchToPath(p.remoteAddr) + s.sentPacketHandler.MigratedPath(p.rcvTime, protocol.ByteCount(s.config.InitialPacketSize)) + maxPacketSize := protocol.ByteCount(protocol.MaxPacketBufferSize) + if s.peerParams.MaxUDPPayloadSize > 0 && s.peerParams.MaxUDPPayloadSize < maxPacketSize { + maxPacketSize = s.peerParams.MaxUDPPayloadSize + } + s.mtuDiscoverer.Reset( + p.rcvTime, + protocol.ByteCount(s.config.InitialPacketSize), + maxPacketSize, + ) + s.conn.ChangeRemoteAddr(p.remoteAddr, p.info) return true, nil } @@ -1336,7 +1387,7 @@ func (s *connection) handleUnpackedLongHeaderPacket( s.tracer.ReceivedLongHeaderPacket(packet.hdr, packetSize, ecn, frames) } } - isAckEliciting, _, err := s.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log, rcvTime) + isAckEliciting, _, _, err := s.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log, rcvTime) if err != nil { return err } @@ -1350,28 +1401,30 @@ func (s *connection) handleUnpackedShortHeaderPacket( ecn protocol.ECN, rcvTime time.Time, log func([]logging.Frame), -) (isNonProbing bool, _ error) { +) (isNonProbing bool, pathChallenge *wire.PathChallengeFrame, _ error) { s.lastPacketReceivedTime = rcvTime s.firstAckElicitingPacketAfterIdleSentTime = time.Time{} s.keepAlivePingSent = false - isAckEliciting, isNonProbing, err := s.handleFrames(data, destConnID, protocol.Encryption1RTT, log, rcvTime) + isAckEliciting, isNonProbing, pathChallenge, err := s.handleFrames(data, destConnID, protocol.Encryption1RTT, log, rcvTime) if err != nil { - return false, err + return false, nil, err } if err := s.receivedPacketHandler.ReceivedPacket(pn, ecn, protocol.Encryption1RTT, rcvTime, isAckEliciting); err != nil { - return false, err + return false, nil, err } - return isNonProbing, nil + return isNonProbing, pathChallenge, nil } +// handleFrames parses the frames, one after the other, and handles them. +// It returns the last PATH_CHALLENGE frame contained in the packet, if any. func (s *connection) handleFrames( data []byte, destConnID protocol.ConnectionID, encLevel protocol.EncryptionLevel, log func([]logging.Frame), rcvTime time.Time, -) (isAckEliciting, isNonProbing bool, _ error) { +) (isAckEliciting, isNonProbing bool, pathChallenge *wire.PathChallengeFrame, _ error) { // Only used for tracing. // If we're not tracing, this slice will always remain empty. var frames []logging.Frame @@ -1383,7 +1436,7 @@ func (s *connection) handleFrames( for len(data) > 0 { l, frame, err := s.frameParser.ParseNext(data, encLevel, s.version) if err != nil { - return false, false, err + return false, false, nil, err } data = data[l:] if frame == nil { @@ -1403,19 +1456,23 @@ func (s *connection) handleFrames( if handleErr != nil { continue } - if err := s.handleFrame(frame, encLevel, destConnID, rcvTime); err != nil { + pc, err := s.handleFrame(frame, encLevel, destConnID, rcvTime) + if err != nil { if log == nil { - return false, false, err + return false, false, nil, err } // If we're logging, we need to keep parsing (but not handling) all frames. handleErr = err } + if pc != nil { + pathChallenge = pc + } } if log != nil { log(frames) if handleErr != nil { - return false, false, handleErr + return false, false, nil, handleErr } } @@ -1425,7 +1482,7 @@ func (s *connection) handleFrames( // and an ACK serialized after that CRYPTO frame. In this case, we still want to process the ACK frame. if !handshakeWasComplete && s.handshakeComplete { if err := s.handleHandshakeComplete(rcvTime); err != nil { - return false, false, err + return false, false, nil, err } } return @@ -1436,7 +1493,7 @@ func (s *connection) handleFrame( encLevel protocol.EncryptionLevel, destConnID protocol.ConnectionID, rcvTime time.Time, -) error { +) (pathChallenge *wire.PathChallengeFrame, _ error) { var err error wire.LogFrame(s.logger, f, false) switch frame := f.(type) { @@ -1465,6 +1522,7 @@ func (s *connection) handleFrame( case *wire.PingFrame: case *wire.PathChallengeFrame: s.handlePathChallengeFrame(frame) + pathChallenge = frame case *wire.PathResponseFrame: err = s.handlePathResponseFrame(frame) case *wire.NewTokenFrame: @@ -1480,7 +1538,7 @@ func (s *connection) handleFrame( default: err = fmt.Errorf("unexpected frame type: %s", reflect.ValueOf(&frame).Elem().Type().Name()) } - return err + return pathChallenge, err } // handlePacket is called by the server with a new packet @@ -1634,11 +1692,35 @@ func (s *connection) handleStopSendingFrame(frame *wire.StopSendingFrame) error } func (s *connection) handlePathChallengeFrame(f *wire.PathChallengeFrame) { - s.queueControlFrame(&wire.PathResponseFrame{Data: f.Data}) + if s.perspective == protocol.PerspectiveClient { + s.queueControlFrame(&wire.PathResponseFrame{Data: f.Data}) + } } func (s *connection) handlePathResponseFrame(f *wire.PathResponseFrame) error { - s.logger.Debugf("received PATH_RESPONSE frame: %v", f.Data) + switch s.perspective { + case protocol.PerspectiveClient: + return s.handlePathResponseFrameClient(f) + case protocol.PerspectiveServer: + return s.handlePathResponseFrameServer(f) + default: + panic("unreachable") + } +} + +func (s *connection) handlePathResponseFrameClient(f *wire.PathResponseFrame) error { + pm := s.pathManagerOutgoing.Load() + if pm == nil { + return &qerr.TransportError{ + ErrorCode: qerr.ProtocolViolation, + ErrorMessage: "unexpected PATH_RESPONSE frame", + } + } + pm.HandlePathResponseFrame(f) + return nil +} + +func (s *connection) handlePathResponseFrameServer(f *wire.PathResponseFrame) error { if s.pathManager == nil { // since we didn't send PATH_CHALLENGEs yet, we don't expect PATH_RESPONSEs return &qerr.TransportError{ @@ -2016,6 +2098,25 @@ func (s *connection) triggerSending(now time.Time) error { } func (s *connection) sendPackets(now time.Time) error { + if s.perspective == protocol.PerspectiveClient && s.handshakeConfirmed { + if pm := s.pathManagerOutgoing.Load(); pm != nil { + connID, frame, tr, ok := pm.NextPathToProbe() + if ok { + probe, buf, err := s.packer.PackPathProbePacket(connID, []ackhandler.Frame{frame}, s.version) + if err != nil { + return err + } + s.logger.Debugf("sending path probe packet from %s", s.LocalAddr()) + s.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false) + s.registerPackedShortHeaderPacket(probe, protocol.ECNNon, now) + tr.WriteTo(buf.Data, s.conn.RemoteAddr()) + // There's (likely) more data to send. Loop around again. + s.scheduleSending() + return nil + } + } + } + // Path MTU Discovery // Can't use GSO, since we need to send a single packet that's larger than our current maximum size. // Performance-wise, this doesn't matter, since we only send a very small (<10) number of @@ -2051,10 +2152,11 @@ func (s *connection) sendPackets(now time.Time) error { if err := s.sendPackedCoalescedPacket(packet, s.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now); err != nil { return err } - sendMode := s.sentPacketHandler.SendMode(now) - if sendMode == ackhandler.SendPacingLimited { + //nolint:exhaustive // only need to handle pacing-related events here + switch s.sentPacketHandler.SendMode(now) { + case ackhandler.SendPacingLimited: s.resetPacingDeadline() - } else if sendMode == ackhandler.SendAny { + case ackhandler.SendAny: s.pacingDeadline = deadlineSendImmediately } return nil @@ -2217,29 +2319,25 @@ func (s *connection) sendProbePacket(sendMode ackhandler.SendMode, now time.Time // Queue probe packets until we actually send out a packet, // or until there are no more packets to queue. var packet *coalescedPacket - for { + for packet == nil { if wasQueued := s.sentPacketHandler.QueueProbePacket(encLevel); !wasQueued { break } var err error - packet, err = s.packer.MaybePackPTOProbePacket(encLevel, s.maxPacketSize(), now, s.version) + packet, err = s.packer.PackPTOProbePacket(encLevel, s.maxPacketSize(), false, now, s.version) if err != nil { return err } - if packet != nil { - break - } } if packet == nil { - s.retransmissionQueue.AddPing(encLevel) var err error - packet, err = s.packer.MaybePackPTOProbePacket(encLevel, s.maxPacketSize(), now, s.version) + packet, err = s.packer.PackPTOProbePacket(encLevel, s.maxPacketSize(), true, now, s.version) if err != nil { return err } } if packet == nil || (len(packet.longHdrPackets) == 0 && packet.shortHdrPacket == nil) { - return fmt.Errorf("connection BUG: couldn't pack %s probe packet", encLevel) + return fmt.Errorf("connection BUG: couldn't pack %s probe packet: %v", encLevel, packet) } return s.sendPackedCoalescedPacket(packet, s.sentPacketHandler.ECNMode(packet.IsOnlyShortHeaderPacket()), now) } @@ -2523,6 +2621,47 @@ func (s *connection) ReceiveDatagram(ctx context.Context) ([]byte, error) { func (s *connection) LocalAddr() net.Addr { return s.conn.LocalAddr() } func (s *connection) RemoteAddr() net.Addr { return s.conn.RemoteAddr() } +func (s *connection) getPathManager() *pathManagerOutgoing { + s.pathManagerOutgoing.CompareAndSwap(nil, + func() *pathManagerOutgoing { // this function is only called if a swap is performed + return newPathManagerOutgoing( + s.connIDManager.GetConnIDForPath, + s.connIDManager.RetireConnIDForPath, + s.scheduleSending, + ) + }(), + ) + return s.pathManagerOutgoing.Load() +} + +func (s *connection) AddPath(t *Transport) (*Path, error) { + if s.perspective == protocol.PerspectiveServer { + return nil, errors.New("server cannot initiate connection migration") + } + if s.peerParams.DisableActiveMigration { + return nil, errors.New("server disabled connection migration") + } + if err := t.init(false); err != nil { + return nil, err + } + return s.getPathManager().NewPath( + t, + 200*time.Millisecond, // initial RTT estimate + func() { + runner := t.connRunner() + s.connIDGenerator.AddConnRunner( + t.id(), + connRunnerCallbacks{ + AddConnectionID: func(connID protocol.ConnectionID) { runner.Add(connID, s) }, + RemoveConnectionID: runner.Remove, + RetireConnectionID: runner.Retire, + ReplaceWithClosed: runner.ReplaceWithClosed, + }, + ) + }, + ), nil +} + func (s *connection) NextConnection(ctx context.Context) (Connection, error) { // The handshake might fail after the server rejected 0-RTT. // This could happen if the Finished message is malformed or never received. diff --git a/vendor/github.com/quic-go/quic-go/http3/client.go b/vendor/github.com/quic-go/quic-go/http3/client.go index 9214bb8066..91f43e4142 100644 --- a/vendor/github.com/quic-go/quic-go/http3/client.go +++ b/vendor/github.com/quic-go/quic-go/http3/client.go @@ -109,24 +109,24 @@ func newClientConn( if c.logger != nil { c.logger.Debug("Setting up connection failed", "error", err) } - c.connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeInternalError), "") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeInternalError), "") } }() if streamHijacker != nil { go c.handleBidirectionalStreams(streamHijacker) } - go c.connection.handleUnidirectionalStreams(uniStreamHijacker) + go c.handleUnidirectionalStreams(uniStreamHijacker) return c } // OpenRequestStream opens a new request stream on the HTTP/3 connection. func (c *ClientConn) OpenRequestStream(ctx context.Context) (RequestStream, error) { - return c.connection.openRequestStream(ctx, c.requestWriter, nil, c.disableCompression, c.maxResponseHeaderBytes) + return c.openRequestStream(ctx, c.requestWriter, nil, c.disableCompression, c.maxResponseHeaderBytes) } func (c *ClientConn) setupConn() error { // open the control stream - str, err := c.connection.OpenUniStream() + str, err := c.OpenUniStream() if err != nil { return err } @@ -140,7 +140,7 @@ func (c *ClientConn) setupConn() error { func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, quic.ConnectionTracingID, quic.Stream, error) (hijacked bool, err error)) { for { - str, err := c.connection.AcceptStream(context.Background()) + str, err := c.AcceptStream(context.Background()) if err != nil { if c.logger != nil { c.logger.Debug("accepting bidirectional stream failed", "error", err) @@ -151,7 +151,7 @@ func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, q r: str, conn: &c.connection, unknownFrameHandler: func(ft FrameType, e error) (processed bool, err error) { - id := c.connection.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) + id := c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) return streamHijacker(ft, id, str, e) }, } @@ -164,7 +164,7 @@ func (c *ClientConn) handleBidirectionalStreams(streamHijacker func(FrameType, q c.logger.Debug("error handling stream", "error", err) } } - c.connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "received HTTP/3 frame on bidirectional stream") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeFrameUnexpected), "received HTTP/3 frame on bidirectional stream") }() } } @@ -210,17 +210,17 @@ func (c *ClientConn) roundTrip(req *http.Request) (*http.Response, error) { connCtx := c.Connection.Context() // wait for the server's SETTINGS frame to arrive select { - case <-c.connection.ReceivedSettings(): + case <-c.ReceivedSettings(): case <-connCtx.Done(): return nil, context.Cause(connCtx) } - if !c.connection.Settings().EnableExtendedConnect { + if !c.Settings().EnableExtendedConnect { return nil, errors.New("http3: server didn't enable Extended CONNECT") } } reqDone := make(chan struct{}) - str, err := c.connection.openRequestStream( + str, err := c.openRequestStream( req.Context(), c.requestWriter, reqDone, @@ -350,7 +350,7 @@ func (c *ClientConn) doRequest(req *http.Request, str *requestStream) (*http.Res } break } - connState := c.connection.ConnectionState().TLS + connState := c.ConnectionState().TLS res.TLS = &connState res.Request = req return res, nil diff --git a/vendor/github.com/quic-go/quic-go/http3/conn.go b/vendor/github.com/quic-go/quic-go/http3/conn.go index bb17a5e5f8..1a9a410e75 100644 --- a/vendor/github.com/quic-go/quic-go/http3/conn.go +++ b/vendor/github.com/quic-go/quic-go/http3/conn.go @@ -106,7 +106,7 @@ func (c *connection) openRequestStream( disableCompression bool, maxHeaderBytes uint64, ) (*requestStream, error) { - str, err := c.Connection.OpenStreamSync(ctx) + str, err := c.OpenStreamSync(ctx) if err != nil { return nil, err } @@ -180,7 +180,7 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co ) for { - str, err := c.Connection.AcceptUniStream(context.Background()) + str, err := c.AcceptUniStream(context.Background()) if err != nil { if c.logger != nil { c.logger.Debug("accepting unidirectional stream failed", "error", err) @@ -191,7 +191,7 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co go func(str quic.ReceiveStream) { streamType, err := quicvarint.Read(quicvarint.NewReader(str)) if err != nil { - id := c.Connection.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) + id := c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID) if hijack != nil && hijack(StreamType(streamType), id, str, err) { return } @@ -205,13 +205,13 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co case streamTypeControlStream: case streamTypeQPACKEncoderStream: if isFirst := rcvdQPACKEncoderStr.CompareAndSwap(false, true); !isFirst { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK encoder stream") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK encoder stream") } // Our QPACK implementation doesn't use the dynamic table yet. return case streamTypeQPACKDecoderStream: if isFirst := rcvdQPACKDecoderStr.CompareAndSwap(false, true); !isFirst { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK decoder stream") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "duplicate QPACK decoder stream") } // Our QPACK implementation doesn't use the dynamic table yet. return @@ -219,17 +219,17 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co switch c.perspective { case protocol.PerspectiveClient: // we never increased the Push ID, so we don't expect any push streams - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "") case protocol.PerspectiveServer: // only the server can push - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "") } return default: if hijack != nil { if hijack( StreamType(streamType), - c.Connection.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID), + c.Context().Value(quic.ConnectionTracingKey).(quic.ConnectionTracingID), str, nil, ) { @@ -267,8 +267,8 @@ func (c *connection) handleUnidirectionalStreams(hijack func(StreamType, quic.Co // If datagram support was enabled on our side as well as on the server side, // we can expect it to have been negotiated both on the transport and on the HTTP/3 layer. // Note: ConnectionState() will block until the handshake is complete (relevant when using 0-RTT). - if c.enableDatagrams && !c.Connection.ConnectionState().SupportsDatagrams { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeSettingsError), "missing QUIC Datagram support") + if c.enableDatagrams && !c.ConnectionState().SupportsDatagrams { + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeSettingsError), "missing QUIC Datagram support") return } go func() { @@ -287,22 +287,22 @@ func (c *connection) sendDatagram(streamID protocol.StreamID, b []byte) error { data := make([]byte, 0, len(b)+8) data = quicvarint.Append(data, uint64(streamID/4)) data = append(data, b...) - return c.Connection.SendDatagram(data) + return c.SendDatagram(data) } func (c *connection) receiveDatagrams() error { for { - b, err := c.Connection.ReceiveDatagram(context.Background()) + b, err := c.ReceiveDatagram(context.Background()) if err != nil { return err } quarterStreamID, n, err := quicvarint.Parse(b) if err != nil { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeDatagramError), "") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeDatagramError), "") return fmt.Errorf("could not read quarter stream id: %w", err) } if quarterStreamID > maxQuarterStreamID { - c.Connection.CloseWithError(quic.ApplicationErrorCode(ErrCodeDatagramError), "") + c.CloseWithError(quic.ApplicationErrorCode(ErrCodeDatagramError), "") return fmt.Errorf("invalid quarter stream id: %w", err) } streamID := protocol.StreamID(4 * quarterStreamID) diff --git a/vendor/github.com/quic-go/quic-go/http3/headers.go b/vendor/github.com/quic-go/quic-go/http3/headers.go index 05d13ff3cb..27af950037 100644 --- a/vendor/github.com/quic-go/quic-go/http3/headers.go +++ b/vendor/github.com/quic-go/quic-go/http3/headers.go @@ -55,24 +55,34 @@ func parseHeaders(headers []qpack.HeaderField, isRequest bool) (header, error) { // all pseudo headers must appear before regular header fields, see section 4.3 of RFC 9114 return header{}, fmt.Errorf("received pseudo header %s after a regular header field", h.Name) } - var isResponsePseudoHeader bool // pseudo headers are either valid for requests or for responses + var isResponsePseudoHeader bool // pseudo headers are either valid for requests or for responses + var isDuplicatePseudoHeader bool // pseudo headers are allowed to appear exactly once switch h.Name { case ":path": + isDuplicatePseudoHeader = hdr.Path != "" hdr.Path = h.Value case ":method": + isDuplicatePseudoHeader = hdr.Method != "" hdr.Method = h.Value case ":authority": + isDuplicatePseudoHeader = hdr.Authority != "" hdr.Authority = h.Value case ":protocol": + isDuplicatePseudoHeader = hdr.Protocol != "" hdr.Protocol = h.Value case ":scheme": + isDuplicatePseudoHeader = hdr.Scheme != "" hdr.Scheme = h.Value case ":status": + isDuplicatePseudoHeader = hdr.Status != "" hdr.Status = h.Value isResponsePseudoHeader = true default: return header{}, fmt.Errorf("unknown pseudo header: %s", h.Name) } + if isDuplicatePseudoHeader { + return header{}, fmt.Errorf("duplicate pseudo header: %s", h.Name) + } if isRequest && isResponsePseudoHeader { return header{}, fmt.Errorf("invalid request pseudo header: %s", h.Name) } diff --git a/vendor/github.com/quic-go/quic-go/http3/http_stream.go b/vendor/github.com/quic-go/quic-go/http3/http_stream.go index 4593d4730b..e030ab9705 100644 --- a/vendor/github.com/quic-go/quic-go/http3/http_stream.go +++ b/vendor/github.com/quic-go/quic-go/http3/http_stream.go @@ -211,8 +211,8 @@ func (s *requestStream) ReadResponse() (*http.Response, error) { } frame, err := fp.ParseNext() if err != nil { - s.Stream.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) - s.Stream.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) + s.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) + s.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) return nil, fmt.Errorf("http3: parsing frame failed: %w", err) } hf, ok := frame.(*headersFrame) @@ -221,14 +221,14 @@ func (s *requestStream) ReadResponse() (*http.Response, error) { return nil, errors.New("http3: expected first frame to be a HEADERS frame") } if hf.Length > s.maxHeaderBytes { - s.Stream.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) - s.Stream.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) + s.CancelRead(quic.StreamErrorCode(ErrCodeFrameError)) + s.CancelWrite(quic.StreamErrorCode(ErrCodeFrameError)) return nil, fmt.Errorf("http3: HEADERS frame too large: %d bytes (max: %d)", hf.Length, s.maxHeaderBytes) } headerBlock := make([]byte, hf.Length) if _, err := io.ReadFull(s.Stream, headerBlock); err != nil { - s.Stream.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete)) - s.Stream.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete)) + s.CancelRead(quic.StreamErrorCode(ErrCodeRequestIncomplete)) + s.CancelWrite(quic.StreamErrorCode(ErrCodeRequestIncomplete)) return nil, fmt.Errorf("http3: failed to read response headers: %w", err) } hfs, err := s.decoder.DecodeFull(headerBlock) @@ -239,8 +239,8 @@ func (s *requestStream) ReadResponse() (*http.Response, error) { } res := s.response if err := updateResponseFromHeaders(res, hfs); err != nil { - s.Stream.CancelRead(quic.StreamErrorCode(ErrCodeMessageError)) - s.Stream.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError)) + s.CancelRead(quic.StreamErrorCode(ErrCodeMessageError)) + s.CancelWrite(quic.StreamErrorCode(ErrCodeMessageError)) return nil, fmt.Errorf("http3: invalid response: %w", err) } diff --git a/vendor/github.com/quic-go/quic-go/http3/server.go b/vendor/github.com/quic-go/quic-go/http3/server.go index 1479609cfc..e3ad559204 100644 --- a/vendor/github.com/quic-go/quic-go/http3/server.go +++ b/vendor/github.com/quic-go/quic-go/http3/server.go @@ -57,55 +57,24 @@ type QUICEarlyListener interface { var _ QUICEarlyListener = &quic.EarlyListener{} -func versionToALPN(v protocol.Version) string { - //nolint:exhaustive // These are all the versions we care about. - switch v { - case protocol.Version1, protocol.Version2: - return NextProtoH3 - default: - return "" - } -} - // ConfigureTLSConfig creates a new tls.Config which can be used -// to create a quic.Listener meant for serving http3. The created -// tls.Config adds the functionality of detecting the used QUIC version -// in order to set the correct ALPN value for the http3 connection. +// to create a quic.Listener meant for serving HTTP/3. func ConfigureTLSConfig(tlsConf *tls.Config) *tls.Config { - // The tls.Config used to setup the quic.Listener needs to have the GetConfigForClient callback set. - // That way, we can get the QUIC version and set the correct ALPN value. - return &tls.Config{ - GetConfigForClient: func(ch *tls.ClientHelloInfo) (*tls.Config, error) { - // determine the ALPN from the QUIC version used - proto := NextProtoH3 - val := ch.Context().Value(quic.QUICVersionContextKey) - if v, ok := val.(quic.Version); ok { - proto = versionToALPN(v) - } - config := tlsConf - if tlsConf.GetConfigForClient != nil { - getConfigForClient := tlsConf.GetConfigForClient - var err error - conf, err := getConfigForClient(ch) - if err != nil { - return nil, err - } - if conf != nil { - config = conf - } - } - if config == nil { - return nil, nil + // Workaround for https://github.com/golang/go/issues/60506. + // This initializes the session tickets _before_ cloning the config. + _, _ = tlsConf.DecryptTicket(nil, tls.ConnectionState{}) + config := tlsConf.Clone() + config.NextProtos = []string{NextProtoH3} + if gfc := config.GetConfigForClient; gfc != nil { + config.GetConfigForClient = func(ch *tls.ClientHelloInfo) (*tls.Config, error) { + conf, err := gfc(ch) + if conf == nil || err != nil { + return conf, err } - // Workaround for https://github.com/golang/go/issues/60506. - // This initializes the session tickets _before_ cloning the config. - _, _ = config.DecryptTicket(nil, tls.ConnectionState{}) - - config = config.Clone() - config.NextProtos = []string{proto} - return config, nil - }, + return ConfigureTLSConfig(conf), nil + } } + return config } // contextKey is a value for use with context.WithValue. It's used as @@ -407,28 +376,10 @@ func (s *Server) generateAltSvcHeader() { } // This code assumes that we will use protocol.SupportedVersions if no quic.Config is passed. - supportedVersions := protocol.SupportedVersions - if s.QUICConfig != nil && len(s.QUICConfig.Versions) > 0 { - supportedVersions = s.QUICConfig.Versions - } - - // keep track of which have been seen so we don't yield duplicate values - seen := make(map[string]struct{}, len(supportedVersions)) - var versionStrings []string - for _, version := range supportedVersions { - if v := versionToALPN(version); len(v) > 0 { - if _, ok := seen[v]; !ok { - versionStrings = append(versionStrings, v) - seen[v] = struct{}{} - } - } - } var altSvc []string addPort := func(port int) { - for _, v := range versionStrings { - altSvc = append(altSvc, fmt.Sprintf(`%s=":%d"; ma=2592000`, v, port)) - } + altSvc = append(altSvc, fmt.Sprintf(`%s=":%d"; ma=2592000`, NextProtoH3, port)) } if s.Port != 0 { diff --git a/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go b/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go index 9cf17f5e68..6edbeedfa4 100644 --- a/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go +++ b/vendor/github.com/quic-go/quic-go/http3/state_tracking_stream.go @@ -90,7 +90,7 @@ func (s *stateTrackingStream) Close() error { } func (s *stateTrackingStream) CancelWrite(e quic.StreamErrorCode) { - s.closeSend(&quic.StreamError{StreamID: s.Stream.StreamID(), ErrorCode: e}) + s.closeSend(&quic.StreamError{StreamID: s.StreamID(), ErrorCode: e}) s.Stream.CancelWrite(e) } @@ -103,7 +103,7 @@ func (s *stateTrackingStream) Write(b []byte) (int, error) { } func (s *stateTrackingStream) CancelRead(e quic.StreamErrorCode) { - s.closeReceive(&quic.StreamError{StreamID: s.Stream.StreamID(), ErrorCode: e}) + s.closeReceive(&quic.StreamError{StreamID: s.StreamID(), ErrorCode: e}) s.Stream.CancelRead(e) } diff --git a/vendor/github.com/quic-go/quic-go/http3/transport.go b/vendor/github.com/quic-go/quic-go/http3/transport.go index b90f11909d..bdedb52403 100644 --- a/vendor/github.com/quic-go/quic-go/http3/transport.go +++ b/vendor/github.com/quic-go/quic-go/http3/transport.go @@ -322,7 +322,7 @@ func (t *Transport) dial(ctx context.Context, hostname string) (quic.EarlyConnec tlsConf.ServerName = sni } // Replace existing ALPNs by H3 - tlsConf.NextProtos = []string{versionToALPN(t.QUICConfig.Versions[0])} + tlsConf.NextProtos = []string{NextProtoH3} dial := t.Dial if dial == nil { diff --git a/vendor/github.com/quic-go/quic-go/interface.go b/vendor/github.com/quic-go/quic-go/interface.go index 7f3c40c281..e144acc6a7 100644 --- a/vendor/github.com/quic-go/quic-go/interface.go +++ b/vendor/github.com/quic-go/quic-go/interface.go @@ -44,31 +44,34 @@ type TokenStore interface { } // Err0RTTRejected is the returned from: -// * Open{Uni}Stream{Sync} -// * Accept{Uni}Stream -// * Stream.Read and Stream.Write +// - Open{Uni}Stream{Sync} +// - Accept{Uni}Stream +// - Stream.Read and Stream.Write +// // when the server rejects a 0-RTT connection attempt. var Err0RTTRejected = errors.New("0-RTT rejected") -// ConnectionTracingKey can be used to associate a ConnectionTracer with a Connection. +// ConnectionTracingKey can be used to associate a [logging.ConnectionTracer] with a [Connection]. // It is set on the Connection.Context() context, // as well as on the context passed to logging.Tracer.NewConnectionTracer. +// // Deprecated: Applications can set their own tracing key using Transport.ConnContext. var ConnectionTracingKey = connTracingCtxKey{} // ConnectionTracingID is the type of the context value saved under the ConnectionTracingKey. +// // Deprecated: Applications can set their own tracing key using Transport.ConnContext. type ConnectionTracingID uint64 type connTracingCtxKey struct{} // QUICVersionContextKey can be used to find out the QUIC version of a TLS handshake from the -// context returned by tls.Config.ClientHelloInfo.Context. +// context returned by tls.Config.ClientInfo.Context. var QUICVersionContextKey = handshake.QUICVersionContextKey -// Stream is the interface implemented by QUIC streams -// In addition to the errors listed on the Connection, -// calls to stream functions can return a StreamError if the stream is canceled. +// Stream is the interface implemented by QUIC streams. +// In addition to the errors listed on the [Connection], +// calls to stream functions can return a [StreamError] if the stream is canceled. type Stream interface { ReceiveStream SendStream @@ -83,12 +86,8 @@ type ReceiveStream interface { // StreamID returns the stream ID. StreamID() StreamID // Read reads data from the stream. - // Read can be made to time out and return a net.Error with Timeout() == true - // after a fixed time limit; see SetDeadline and SetReadDeadline. - // If the stream was canceled by the peer, the error is a StreamError and - // Remote == true. - // If the connection was closed due to a timeout, the error satisfies - // the net.Error interface, and Timeout() will be true. + // Read can be made to time out using SetDeadline and SetReadDeadline. + // If the stream was canceled, the error is a StreamError. io.Reader // CancelRead aborts receiving on this stream. // It will ask the peer to stop transmitting stream data. @@ -106,12 +105,8 @@ type SendStream interface { // StreamID returns the stream ID. StreamID() StreamID // Write writes data to the stream. - // Write can be made to time out and return a net.Error with Timeout() == true - // after a fixed time limit; see SetDeadline and SetWriteDeadline. - // If the stream was canceled by the peer, the error is a StreamError and - // Remote == true. - // If the connection was closed due to a timeout, the error satisfies - // the net.Error interface, and Timeout() will be true. + // Write can be made to time out using SetDeadline and SetWriteDeadline. + // If the stream was canceled, the error is a StreamError. io.Writer // Close closes the write-direction of the stream. // Future calls to Write are not permitted after calling Close. @@ -141,20 +136,16 @@ type SendStream interface { // A Connection is a QUIC connection between two peers. // Calls to the connection (and to streams) can return the following types of errors: -// * ApplicationError: for errors triggered by the application running on top of QUIC -// * TransportError: for errors triggered by the QUIC transport (in many cases a misbehaving peer) -// * IdleTimeoutError: when the peer goes away unexpectedly (this is a net.Error timeout error) -// * HandshakeTimeoutError: when the cryptographic handshake takes too long (this is a net.Error timeout error) -// * StatelessResetError: when we receive a stateless reset -// * VersionNegotiationError: returned by the client, when there's no version overlap between the peers +// - [ApplicationError]: for errors triggered by the application running on top of QUIC +// - [TransportError]: for errors triggered by the QUIC transport (in many cases a misbehaving peer) +// - [IdleTimeoutError]: when the peer goes away unexpectedly (this is a [net.Error] timeout error) +// - [HandshakeTimeoutError]: when the cryptographic handshake takes too long (this is a [net.Error] timeout error) +// - [StatelessResetError]: when we receive a stateless reset +// - [VersionNegotiationError]: returned by the client, when there's no version overlap between the peers type Connection interface { // AcceptStream returns the next stream opened by the peer, blocking until one is available. - // If the connection was closed due to a timeout, the error satisfies - // the net.Error interface, and Timeout() will be true. AcceptStream(context.Context) (Stream, error) // AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available. - // If the connection was closed due to a timeout, the error satisfies - // the net.Error interface, and Timeout() will be true. AcceptUniStream(context.Context) (ReceiveStream, error) // OpenStream opens a new bidirectional QUIC stream. // There is no signaling to the peer about new streams: @@ -205,6 +196,8 @@ type Connection interface { SendDatagram(payload []byte) error // ReceiveDatagram gets a message received in a datagram, as specified in RFC 9221. ReceiveDatagram(context.Context) ([]byte, error) + + AddPath(*Transport) (*Path, error) } // An EarlyConnection is a connection that is handshaking. @@ -234,27 +227,22 @@ type TokenGeneratorKey = handshake.TokenProtectorKey // as they are allowed by RFC 8999. type ConnectionID = protocol.ConnectionID -// ConnectionIDFromBytes interprets b as a Connection ID. It panics if b is +// ConnectionIDFromBytes interprets b as a [ConnectionID]. It panics if b is // longer than 20 bytes. func ConnectionIDFromBytes(b []byte) ConnectionID { return protocol.ParseConnectionID(b) } -// A ConnectionIDGenerator is an interface that allows clients to implement their own format -// for the Connection IDs that servers/clients use as SrcConnectionID in QUIC packets. -// -// Connection IDs generated by an implementation should always produce IDs of constant size. +// A ConnectionIDGenerator allows the application to take control over the generation of Connection IDs. +// Connection IDs generated by an implementation must be of constant length. type ConnectionIDGenerator interface { - // GenerateConnectionID generates a new ConnectionID. - // Generated ConnectionIDs should be unique and observers should not be able to correlate two ConnectionIDs. + // GenerateConnectionID generates a new Connection ID. + // Generated Connection IDs must be unique and observers should not be able to correlate two Connection IDs. GenerateConnectionID() (ConnectionID, error) - // ConnectionIDLen tells what is the length of the ConnectionIDs generated by the implementation of - // this interface. - // Effectively, this means that implementations of ConnectionIDGenerator must always return constant-size - // connection IDs. Valid lengths are between 0 and 20 and calls to GenerateConnectionID. - // 0-length ConnectionsIDs can be used when an endpoint (server or client) does not require multiplexing connections - // in the presence of a connection migration environment. + // ConnectionIDLen returns the length of Connection IDs generated by this implementation. + // Implementations must return constant-length Connection IDs with lengths between 0 and 20 bytes. + // A length of 0 can only be used when an endpoint doesn't need to multiplex connections during migration. ConnectionIDLen() int } @@ -262,7 +250,7 @@ type ConnectionIDGenerator interface { type Config struct { // GetConfigForClient is called for incoming connections. // If the error is not nil, the connection attempt is refused. - GetConfigForClient func(info *ClientHelloInfo) (*Config, error) + GetConfigForClient func(info *ClientInfo) (*Config, error) // The QUIC versions that can be negotiated. // If not set, it uses all versions available. Versions []Version @@ -323,10 +311,10 @@ type Config struct { // If set to 0, then no keep alive is sent. Otherwise, the keep alive is sent on that period (or at most // every half of MaxIdleTimeout, whichever is smaller). KeepAlivePeriod time.Duration - // InitialPacketSize is the initial size of packets sent. - // It is usually not necessary to manually set this value, - // since Path MTU discovery very quickly finds the path's MTU. - // If set too high, the path might not support packets that large, leading to a timeout of the QUIC handshake. + // InitialPacketSize is the initial size (and the lower limit) for packets sent. + // Under most circumstances, it is not necessary to manually set this value, + // since path MTU discovery quickly finds the path's MTU. + // If set too high, the path might not support packets of that size, leading to a timeout of the QUIC handshake. // Values below 1200 are invalid. InitialPacketSize uint16 // DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899). @@ -342,7 +330,12 @@ type Config struct { } // ClientHelloInfo contains information about an incoming connection attempt. -type ClientHelloInfo struct { +// +// Deprecated: Use ClientInfo instead. +type ClientHelloInfo = ClientInfo + +// ClientInfo contains information about an incoming connection attempt. +type ClientInfo struct { // RemoteAddr is the remote address on the Initial packet. // Unless AddrVerified is set, the address is not yet verified, and could be a spoofed IP address. RemoteAddr net.Addr @@ -352,7 +345,7 @@ type ClientHelloInfo struct { AddrVerified bool } -// ConnectionState records basic details about a QUIC connection +// ConnectionState records basic details about a QUIC connection. type ConnectionState struct { // TLS contains information about the TLS connection state, incl. the tls.ConnectionState. TLS tls.ConnectionState @@ -365,6 +358,6 @@ type ConnectionState struct { Used0RTT bool // Version is the QUIC version of the QUIC connection. Version Version - // GSO says if generic segmentation offload is used + // GSO says if generic segmentation offload is used. GSO bool } diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go index 83d2736ac1..a53be7d70c 100644 --- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go +++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_handler.go @@ -584,14 +584,15 @@ func (h *sentPacketHandler) setLossDetectionTimer(now time.Time) { newAlarm := h.lossDetectionTime(now) h.alarm = newAlarm - if newAlarm.Time.IsZero() && !oldAlarm.Time.IsZero() { + hasAlarm := !newAlarm.Time.IsZero() + if !hasAlarm && !oldAlarm.Time.IsZero() { h.logger.Debugf("Canceling loss detection timer.") if h.tracer != nil && h.tracer.LossTimerCanceled != nil { h.tracer.LossTimerCanceled() } } - if h.tracer != nil && h.tracer.SetLossTimer != nil && newAlarm != oldAlarm { + if hasAlarm && h.tracer != nil && h.tracer.SetLossTimer != nil && newAlarm != oldAlarm { h.tracer.SetLossTimer(newAlarm.TimerType, newAlarm.EncryptionLevel, newAlarm.Time) } } @@ -636,7 +637,7 @@ func (h *sentPacketHandler) lossDetectionTime(now time.Time) alarmTimer { return alarmTimer{ Time: pathProbeLossTime, TimerType: logging.TimerTypePathProbe, - EncryptionLevel: encLevel, + EncryptionLevel: protocol.Encryption1RTT, } } return alarmTimer{} diff --git a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go index bbeb78892f..c550e75a9a 100644 --- a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go +++ b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/connection_flow_controller.go @@ -61,8 +61,8 @@ func (c *connectionFlowController) AddBytesRead(n protocol.ByteCount) (hasWindow c.mutex.Lock() defer c.mutex.Unlock() - c.baseFlowController.addBytesRead(n) - return c.baseFlowController.hasWindowUpdate() + c.addBytesRead(n) + return c.hasWindowUpdate() } func (c *connectionFlowController) GetWindowUpdate(now time.Time) protocol.ByteCount { @@ -70,7 +70,7 @@ func (c *connectionFlowController) GetWindowUpdate(now time.Time) protocol.ByteC defer c.mutex.Unlock() oldWindowSize := c.receiveWindowSize - offset := c.baseFlowController.getWindowUpdate(now) + offset := c.getWindowUpdate(now) if c.logger.Debug() && oldWindowSize < c.receiveWindowSize { c.logger.Debugf("Increasing receive flow control window for the connection to %d kB", c.receiveWindowSize/(1<<10)) } diff --git a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go index ba0051224f..968e9a5b5f 100644 --- a/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go +++ b/vendor/github.com/quic-go/quic-go/internal/flowcontrol/stream_flow_controller.go @@ -100,7 +100,7 @@ func (c *streamFlowController) UpdateHighestReceived(offset protocol.ByteCount, func (c *streamFlowController) AddBytesRead(n protocol.ByteCount) (hasStreamWindowUpdate, hasConnWindowUpdate bool) { c.mutex.Lock() - c.baseFlowController.addBytesRead(n) + c.addBytesRead(n) hasStreamWindowUpdate = c.shouldQueueWindowUpdate() c.mutex.Unlock() hasConnWindowUpdate = c.connection.AddBytesRead(n) @@ -145,7 +145,7 @@ func (c *streamFlowController) GetWindowUpdate(now time.Time) protocol.ByteCount defer c.mutex.Unlock() oldWindowSize := c.receiveWindowSize - offset := c.baseFlowController.getWindowUpdate(now) + offset := c.getWindowUpdate(now) if c.receiveWindowSize > oldWindowSize { // auto-tuning enlarged the window size c.logger.Debugf("Increasing receive flow control window for stream %d to %d", c.streamID, c.receiveWindowSize) c.connection.EnsureMinimumWindowSize(protocol.ByteCount(float64(c.receiveWindowSize)*protocol.ConnectionFlowControlMultiplier), now) diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go b/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go index d056cb9dea..b1109ff436 100644 --- a/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go +++ b/vendor/github.com/quic-go/quic-go/internal/protocol/protocol.go @@ -123,6 +123,10 @@ const MinUnknownVersionPacketSize = MinInitialPacketSize // MinStatelessResetSize is the minimum size of a stateless reset packet that we send const MinStatelessResetSize = 1 /* first byte */ + 20 /* max. conn ID length */ + 4 /* max. packet number length */ + 1 /* min. payload length */ + 16 /* token */ +// MinReceivedStatelessResetSize is the minimum size of a received stateless reset, +// as specified in section 10.3 of RFC 9000. +const MinReceivedStatelessResetSize = 5 + 16 + // MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet. const MinConnectionIDLenInitial = 8 diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/version.go b/vendor/github.com/quic-go/quic-go/internal/protocol/version.go index 025ade9b47..646587f312 100644 --- a/vendor/github.com/quic-go/quic-go/internal/protocol/version.go +++ b/vendor/github.com/quic-go/quic-go/internal/protocol/version.go @@ -1,13 +1,12 @@ package protocol import ( + "crypto/rand" "encoding/binary" "fmt" "math" + mrand "math/rand/v2" "sync" - "time" - - "golang.org/x/exp/rand" ) // Version is a version number as int @@ -90,13 +89,22 @@ func ChooseSupportedVersion(ours, theirs []Version) (Version, bool) { var ( versionNegotiationMx sync.Mutex - versionNegotiationRand = rand.New(rand.NewSource(uint64(time.Now().UnixNano()))) + versionNegotiationRand mrand.Rand ) +func init() { + var seed [16]byte + rand.Read(seed[:]) + versionNegotiationRand = *mrand.New(mrand.NewPCG( + binary.BigEndian.Uint64(seed[:8]), + binary.BigEndian.Uint64(seed[8:]), + )) +} + // generateReservedVersion generates a reserved version (v & 0x0f0f0f0f == 0x0a0a0a0a) func generateReservedVersion() Version { var b [4]byte - _, _ = versionNegotiationRand.Read(b[:]) // ignore the error here. Failure to read random data doesn't break anything + binary.BigEndian.PutUint32(b[:], versionNegotiationRand.Uint32()) return Version((binary.BigEndian.Uint32(b[:]) | 0x0a0a0a0a) & 0xfafafafa) } @@ -105,7 +113,7 @@ func generateReservedVersion() Version { func GetGreasedVersions(supported []Version) []Version { versionNegotiationMx.Lock() defer versionNegotiationMx.Unlock() - randPos := rand.Intn(len(supported) + 1) + randPos := versionNegotiationRand.IntN(len(supported) + 1) greased := make([]Version, len(supported)+1) copy(greased, supported[:randPos]) greased[randPos] = generateReservedVersion() diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go b/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go index b5b9d6fc7d..80ebfecb17 100644 --- a/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go +++ b/vendor/github.com/quic-go/quic-go/internal/utils/buffered_write_closer.go @@ -19,7 +19,7 @@ func NewBufferedWriteCloser(writer *bufio.Writer, closer io.Closer) io.WriteClos } func (h bufferedWriteCloser) Close() error { - if err := h.Writer.Flush(); err != nil { + if err := h.Flush(); err != nil { return err } return h.Closer.Close() diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go index 852d46ef14..6f2287f44b 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/new_connection_id_frame.go @@ -30,7 +30,7 @@ func parseNewConnectionIDFrame(b []byte, _ protocol.Version) (*NewConnectionIDFr } b = b[l:] if ret > seq { - //nolint:stylecheck + //nolint:staticcheck // SA1021: Retire Prior To is the name of the field return nil, 0, fmt.Errorf("Retire Prior To value (%d) larger than Sequence Number (%d)", ret, seq) } if len(b) == 0 { diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go b/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go index cee74b8fa4..d39189a0d5 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/transport_parameters.go @@ -245,11 +245,15 @@ func (p *TransportParameters) readPreferredAddress(b []byte, expectedLen int) er copy(ipv4[:], b[:4]) port4 := binary.BigEndian.Uint16(b[4:]) b = b[4+2:] - pa.IPv4 = netip.AddrPortFrom(netip.AddrFrom4(ipv4), port4) + if port4 != 0 && ipv4 != [4]byte{} { + pa.IPv4 = netip.AddrPortFrom(netip.AddrFrom4(ipv4), port4) + } var ipv6 [16]byte copy(ipv6[:], b[:16]) port6 := binary.BigEndian.Uint16(b[16:]) - pa.IPv6 = netip.AddrPortFrom(netip.AddrFrom16(ipv6), port6) + if port6 != 0 && ipv6 != [16]byte{} { + pa.IPv6 = netip.AddrPortFrom(netip.AddrFrom16(ipv6), port6) + } b = b[16+2:] connIDLen := int(b[0]) b = b[1:] @@ -391,12 +395,20 @@ func (p *TransportParameters) Marshal(pers protocol.Perspective) []byte { if p.PreferredAddress != nil { b = quicvarint.Append(b, uint64(preferredAddressParameterID)) b = quicvarint.Append(b, 4+2+16+2+1+uint64(p.PreferredAddress.ConnectionID.Len())+16) - ip4 := p.PreferredAddress.IPv4.Addr().As4() - b = append(b, ip4[:]...) - b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv4.Port()) - ip6 := p.PreferredAddress.IPv6.Addr().As16() - b = append(b, ip6[:]...) - b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv6.Port()) + if p.PreferredAddress.IPv4.IsValid() { + ipv4 := p.PreferredAddress.IPv4.Addr().As4() + b = append(b, ipv4[:]...) + b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv4.Port()) + } else { + b = append(b, make([]byte, 6)...) + } + if p.PreferredAddress.IPv6.IsValid() { + ipv6 := p.PreferredAddress.IPv6.Addr().As16() + b = append(b, ipv6[:]...) + b = binary.BigEndian.AppendUint16(b, p.PreferredAddress.IPv6.Port()) + } else { + b = append(b, make([]byte, 18)...) + } b = append(b, uint8(p.PreferredAddress.ConnectionID.Len())) b = append(b, p.PreferredAddress.ConnectionID.Bytes()...) b = append(b, p.PreferredAddress.StatelessResetToken[:]...) diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go b/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go index a551aa8c95..407cb629cc 100644 --- a/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go +++ b/vendor/github.com/quic-go/quic-go/internal/wire/version_negotiation.go @@ -16,11 +16,11 @@ func ParseVersionNegotiationPacket(b []byte) (dest, src protocol.ArbitraryLenCon } b = b[n:] if len(b) == 0 { - //nolint:stylecheck + //nolint:staticcheck // SA1021: the packet is called Version Negotiation packet return nil, nil, nil, errors.New("Version Negotiation packet has empty version list") } if len(b)%4 != 0 { - //nolint:stylecheck + //nolint:staticcheck // SA1021: the packet is called Version Negotiation packet return nil, nil, nil, errors.New("Version Negotiation packet has a version list with an invalid length") } versions := make([]protocol.Version, len(b)/4) diff --git a/vendor/github.com/quic-go/quic-go/packet_packer.go b/vendor/github.com/quic-go/quic-go/packet_packer.go index 720f195831..e84a6c025e 100644 --- a/vendor/github.com/quic-go/quic-go/packet_packer.go +++ b/vendor/github.com/quic-go/quic-go/packet_packer.go @@ -5,10 +5,9 @@ import ( "encoding/binary" "errors" "fmt" + "math/rand/v2" "time" - "golang.org/x/exp/rand" - "github.com/quic-go/quic-go/internal/ackhandler" "github.com/quic-go/quic-go/internal/handshake" "github.com/quic-go/quic-go/internal/protocol" @@ -21,11 +20,11 @@ var errNothingToPack = errors.New("nothing to pack") type packer interface { PackCoalescedPacket(onlyAck bool, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (*coalescedPacket, error) PackAckOnlyPacket(maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) - AppendPacket(buf *packetBuffer, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, error) - MaybePackPTOProbePacket(protocol.EncryptionLevel, protocol.ByteCount, time.Time, protocol.Version) (*coalescedPacket, error) + AppendPacket(_ *packetBuffer, maxPacketSize protocol.ByteCount, now time.Time, v protocol.Version) (shortHeaderPacket, error) + PackPTOProbePacket(_ protocol.EncryptionLevel, _ protocol.ByteCount, addPingIfEmpty bool, now time.Time, v protocol.Version) (*coalescedPacket, error) PackConnectionClose(*qerr.TransportError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error) PackApplicationClose(*qerr.ApplicationError, protocol.ByteCount, protocol.Version) (*coalescedPacket, error) - PackPathProbePacket(protocol.ConnectionID, ackhandler.Frame, protocol.Version) (shortHeaderPacket, *packetBuffer, error) + PackPathProbePacket(protocol.ConnectionID, []ackhandler.Frame, protocol.Version) (shortHeaderPacket, *packetBuffer, error) PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) SetToken([]byte) @@ -152,7 +151,7 @@ func newPacketPacker( datagramQueue *datagramQueue, perspective protocol.Perspective, ) *packetPacker { - var b [8]byte + var b [16]byte _, _ = crand.Read(b[:]) return &packetPacker{ @@ -166,7 +165,7 @@ func newPacketPacker( perspective: perspective, framer: framer, acks: acks, - rand: *rand.New(rand.NewSource(binary.BigEndian.Uint64(b[:]))), + rand: *rand.New(rand.NewPCG(binary.BigEndian.Uint64(b[:8]), binary.BigEndian.Uint64(b[8:]))), pnManager: packetNumberManager, } } @@ -348,6 +347,7 @@ func (p *packetPacker) PackCoalescedPacket(onlyAck bool, maxSize protocol.ByteCo maxSize-protocol.ByteCount(initialSealer.Overhead()), protocol.EncryptionInitial, now, + false, onlyAck, true, v, @@ -370,6 +370,7 @@ func (p *packetPacker) PackCoalescedPacket(onlyAck bool, maxSize protocol.ByteCo maxSize-size-protocol.ByteCount(handshakeSealer.Overhead()), protocol.EncryptionHandshake, now, + false, onlyAck, size == 0, v, @@ -497,6 +498,7 @@ func (p *packetPacker) maybeGetCryptoPacket( maxPacketSize protocol.ByteCount, encLevel protocol.EncryptionLevel, now time.Time, + addPingIfEmpty bool, onlyAck, ackAllowed bool, v protocol.Version, ) (*wire.ExtendedHeader, payload) { @@ -511,31 +513,32 @@ func (p *packetPacker) maybeGetCryptoPacket( } var s *cryptoStream - var handler ackhandler.FrameHandler - var hasRetransmission bool //nolint:exhaustive // Initial and Handshake are the only two encryption levels here. switch encLevel { case protocol.EncryptionInitial: s = p.initialStream - handler = p.retransmissionQueue.InitialAckHandler() - hasRetransmission = p.retransmissionQueue.HasInitialData() case protocol.EncryptionHandshake: s = p.handshakeStream - handler = p.retransmissionQueue.HandshakeAckHandler() - hasRetransmission = p.retransmissionQueue.HasHandshakeData() } - hasData := s.HasData() + handler := p.retransmissionQueue.AckHandler(encLevel) + hasRetransmission := p.retransmissionQueue.HasData(encLevel) + var ack *wire.AckFrame if ackAllowed { ack = p.acks.GetAckFrame(encLevel, now, !hasRetransmission && !hasData) } + var pl payload if !hasData && !hasRetransmission && ack == nil { - // nothing to send - return nil, payload{} + if !addPingIfEmpty { + // nothing to send + return nil, payload{} + } + ping := &wire.PingFrame{} + pl.frames = append(pl.frames, ackhandler.Frame{Frame: ping, Handler: emptyHandler{}}) + pl.length += ping.Length(v) } - var pl payload if ack != nil { pl.ack = ack pl.length = ack.Length(v) @@ -545,44 +548,33 @@ func (p *packetPacker) maybeGetCryptoPacket( maxPacketSize -= hdr.GetLength(v) if hasRetransmission { for { - var f ackhandler.Frame - //nolint:exhaustive // 0-RTT packets can't contain any retransmissions - switch encLevel { - case protocol.EncryptionInitial: - f.Frame = p.retransmissionQueue.GetInitialFrame(maxPacketSize, v) - f.Handler = p.retransmissionQueue.InitialAckHandler() - case protocol.EncryptionHandshake: - f.Frame = p.retransmissionQueue.GetHandshakeFrame(maxPacketSize, v) - f.Handler = p.retransmissionQueue.HandshakeAckHandler() - } - if f.Frame == nil { + frame := p.retransmissionQueue.GetFrame(encLevel, maxPacketSize, v) + if frame == nil { break } - pl.frames = append(pl.frames, f) - frameLen := f.Frame.Length(v) + pl.frames = append(pl.frames, ackhandler.Frame{ + Frame: frame, + Handler: p.retransmissionQueue.AckHandler(encLevel), + }) + frameLen := frame.Length(v) pl.length += frameLen maxPacketSize -= frameLen } } else if s.HasData() { cf := s.PopCryptoFrame(maxPacketSize) - pl.frames = []ackhandler.Frame{{Frame: cf, Handler: handler}} + pl.frames = append(pl.frames, ackhandler.Frame{Frame: cf, Handler: handler}) pl.length += cf.Length(v) } return hdr, pl } -func (p *packetPacker) maybeGetAppDataPacketFor0RTT( - sealer sealer, - maxPacketSize protocol.ByteCount, - now time.Time, - v protocol.Version, -) (*wire.ExtendedHeader, payload) { +func (p *packetPacker) maybeGetAppDataPacketFor0RTT(sealer sealer, maxSize protocol.ByteCount, now time.Time, v protocol.Version) (*wire.ExtendedHeader, payload) { if p.perspective != protocol.PerspectiveClient { return nil, payload{} } hdr := p.getLongHeader(protocol.Encryption0RTT, v) - maxPayloadSize := maxPacketSize - hdr.GetLength(v) - protocol.ByteCount(sealer.Overhead()) + maxPayloadSize := maxSize - hdr.GetLength(v) - protocol.ByteCount(sealer.Overhead()) return hdr, p.maybeGetAppDataPacket(maxPayloadSize, false, false, now, v) } @@ -626,7 +618,7 @@ func (p *packetPacker) maybeGetAppDataPacket( } func (p *packetPacker) composeNextPacket( - maxFrameSize protocol.ByteCount, + maxPayloadSize protocol.ByteCount, onlyAck, ackAllowed bool, now time.Time, v protocol.Version, @@ -639,7 +631,7 @@ func (p *packetPacker) composeNextPacket( } hasData := p.framer.HasData() - hasRetransmission := p.retransmissionQueue.HasAppData() + hasRetransmission := p.retransmissionQueue.HasData(protocol.Encryption1RTT) var hasAck bool var pl payload @@ -654,7 +646,7 @@ func (p *packetPacker) composeNextPacket( if p.datagramQueue != nil { if f := p.datagramQueue.Peek(); f != nil { size := f.Length(v) - if size <= maxFrameSize-pl.length { // DATAGRAM frame fits + if size <= maxPayloadSize-pl.length { // DATAGRAM frame fits pl.frames = append(pl.frames, ackhandler.Frame{Frame: f}) pl.length += size p.datagramQueue.Pop() @@ -674,15 +666,15 @@ func (p *packetPacker) composeNextPacket( if hasRetransmission { for { - remainingLen := maxFrameSize - pl.length + remainingLen := maxPayloadSize - pl.length if remainingLen < protocol.MinStreamFrameSize { break } - f := p.retransmissionQueue.GetAppDataFrame(remainingLen, v) + f := p.retransmissionQueue.GetFrame(protocol.Encryption1RTT, remainingLen, v) if f == nil { break } - pl.frames = append(pl.frames, ackhandler.Frame{Frame: f, Handler: p.retransmissionQueue.AppDataAckHandler()}) + pl.frames = append(pl.frames, ackhandler.Frame{Frame: f, Handler: p.retransmissionQueue.AckHandler(protocol.Encryption1RTT)}) pl.length += f.Length(v) } } @@ -690,7 +682,7 @@ func (p *packetPacker) composeNextPacket( if hasData { var lengthAdded protocol.ByteCount startLen := len(pl.frames) - pl.frames, pl.streamFrames, lengthAdded = p.framer.Append(pl.frames, pl.streamFrames, maxFrameSize-pl.length, now, v) + pl.frames, pl.streamFrames, lengthAdded = p.framer.Append(pl.frames, pl.streamFrames, maxPayloadSize-pl.length, now, v) pl.length += lengthAdded // add handlers for the control frames that were added for i := startLen; i < len(pl.frames); i++ { @@ -702,40 +694,23 @@ func (p *packetPacker) composeNextPacket( // Path probing is currently not supported, therefore we don't need to set the OnAcked callback yet. // PATH_CHALLENGE and PATH_RESPONSE are never retransmitted. default: - pl.frames[i].Handler = p.retransmissionQueue.AppDataAckHandler() + // we might be packing a 0-RTT packet, but we need to use the 1-RTT ack handler anyway + pl.frames[i].Handler = p.retransmissionQueue.AckHandler(protocol.Encryption1RTT) } } } return pl } -func (p *packetPacker) MaybePackPTOProbePacket( +func (p *packetPacker) PackPTOProbePacket( encLevel protocol.EncryptionLevel, maxPacketSize protocol.ByteCount, + addPingIfEmpty bool, now time.Time, v protocol.Version, ) (*coalescedPacket, error) { if encLevel == protocol.Encryption1RTT { - s, err := p.cryptoSetup.Get1RTTSealer() - if err != nil { - return nil, err - } - kp := s.KeyPhase() - connID := p.getDestConnID() - pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT) - hdrLen := wire.ShortHeaderLen(connID, pnLen) - pl := p.maybeGetAppDataPacket(maxPacketSize-protocol.ByteCount(s.Overhead())-hdrLen, false, true, now, v) - if pl.length == 0 { - return nil, nil - } - buffer := getPacketBuffer() - packet := &coalescedPacket{buffer: buffer} - shp, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, 0, maxPacketSize, s, false, v) - if err != nil { - return nil, err - } - packet.shortHdrPacket = &shp - return packet, nil + return p.packPTOProbePacket1RTT(maxPacketSize, addPingIfEmpty, now, v) } var sealer handshake.LongHeaderSealer @@ -756,7 +731,15 @@ func (p *packetPacker) MaybePackPTOProbePacket( default: panic("unknown encryption level") } - hdr, pl := p.maybeGetCryptoPacket(maxPacketSize-protocol.ByteCount(sealer.Overhead()), encLevel, now, false, true, v) + hdr, pl := p.maybeGetCryptoPacket( + maxPacketSize-protocol.ByteCount(sealer.Overhead()), + encLevel, + now, + addPingIfEmpty, + false, + true, + v, + ) if pl.length == 0 { return nil, nil } @@ -776,6 +759,34 @@ func (p *packetPacker) MaybePackPTOProbePacket( return packet, nil } +func (p *packetPacker) packPTOProbePacket1RTT(maxPacketSize protocol.ByteCount, addPingIfEmpty bool, now time.Time, v protocol.Version) (*coalescedPacket, error) { + s, err := p.cryptoSetup.Get1RTTSealer() + if err != nil { + return nil, err + } + kp := s.KeyPhase() + connID := p.getDestConnID() + pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT) + hdrLen := wire.ShortHeaderLen(connID, pnLen) + pl := p.maybeGetAppDataPacket(maxPacketSize-protocol.ByteCount(s.Overhead())-hdrLen, false, true, now, v) + if pl.length == 0 { + if !addPingIfEmpty { + return nil, nil + } + ping := &wire.PingFrame{} + pl.frames = append(pl.frames, ackhandler.Frame{Frame: ping, Handler: emptyHandler{}}) + pl.length += ping.Length(v) + } + buffer := getPacketBuffer() + packet := &coalescedPacket{buffer: buffer} + shp, err := p.appendShortHeaderPacket(buffer, connID, pn, pnLen, kp, pl, 0, maxPacketSize, s, false, v) + if err != nil { + return nil, err + } + packet.shortHdrPacket = &shp + return packet, nil +} + func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) { pl := payload{ frames: []ackhandler.Frame{ping}, @@ -794,16 +805,20 @@ func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.B return packet, buffer, err } -func (p *packetPacker) PackPathProbePacket(connID protocol.ConnectionID, f ackhandler.Frame, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) { +func (p *packetPacker) PackPathProbePacket(connID protocol.ConnectionID, frames []ackhandler.Frame, v protocol.Version) (shortHeaderPacket, *packetBuffer, error) { pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT) buf := getPacketBuffer() s, err := p.cryptoSetup.Get1RTTSealer() if err != nil { return shortHeaderPacket{}, nil, err } + var l protocol.ByteCount + for _, f := range frames { + l += f.Frame.Length(v) + } payload := payload{ - frames: []ackhandler.Frame{f}, - length: f.Frame.Length(v), + frames: frames, + length: l, } padding := protocol.MinInitialPacketSize - p.shortHeaderPacketLength(connID, pnLen, payload) - protocol.ByteCount(s.Overhead()) packet, err := p.appendShortHeaderPacket(buf, connID, pn, pnLen, s.KeyPhase(), payload, padding, protocol.MinInitialPacketSize, s, false, v) @@ -979,3 +994,10 @@ func (p *packetPacker) encryptPacket(raw []byte, sealer sealer, pn protocol.Pack func (p *packetPacker) SetToken(token []byte) { p.token = token } + +type emptyHandler struct{} + +var _ ackhandler.FrameHandler = emptyHandler{} + +func (emptyHandler) OnAcked(wire.Frame) {} +func (emptyHandler) OnLost(wire.Frame) {} diff --git a/vendor/github.com/quic-go/quic-go/packet_unpacker.go b/vendor/github.com/quic-go/quic-go/packet_unpacker.go index 9e0fa9d90e..2f607fbd8c 100644 --- a/vendor/github.com/quic-go/quic-go/packet_unpacker.go +++ b/vendor/github.com/quic-go/quic-go/packet_unpacker.go @@ -197,8 +197,7 @@ func (u *packetUnpacker) unpackLongHeader(hd headerDecryptor, hdr *wire.Header, func unpackLongHeader(hd headerDecryptor, hdr *wire.Header, data []byte) (*wire.ExtendedHeader, error) { hdrLen := hdr.ParsedLen() if protocol.ByteCount(len(data)) < hdrLen+4+16 { - //nolint:stylecheck - return nil, fmt.Errorf("Packet too small. Expected at least 20 bytes after the header, got %d", protocol.ByteCount(len(data))-hdrLen) + return nil, fmt.Errorf("packet too small, expected at least 20 bytes after the header, got %d", protocol.ByteCount(len(data))-hdrLen) } // The packet number can be up to 4 bytes long, but we won't know the length until we decrypt it. // 1. save a copy of the 4 bytes diff --git a/vendor/github.com/quic-go/quic-go/path_manager.go b/vendor/github.com/quic-go/quic-go/path_manager.go index 6d940921dd..34096654b1 100644 --- a/vendor/github.com/quic-go/quic-go/path_manager.go +++ b/vendor/github.com/quic-go/quic-go/path_manager.go @@ -3,6 +3,8 @@ package quic import ( "crypto/rand" "net" + "slices" + "time" "github.com/quic-go/quic-go/internal/ackhandler" "github.com/quic-go/quic-go/internal/protocol" @@ -12,10 +14,23 @@ import ( type pathID int64 +const invalidPathID pathID = -1 + +// Maximum number of paths to keep track of. +// If the peer probes another path (before the pathTimeout of an existing path expires), +// this probing attempt is ignored. const maxPaths = 3 +// If no packet is received for a path for pathTimeout, +// the path can be evicted when the peer probes another path. +// This prevents an attacker from churning through paths by duplicating packets and +// sending them with spoofed source addresses. +const pathTimeout = 5 * time.Second + type path struct { + id pathID addr net.Addr + lastPacketTime time.Time pathChallenge [8]byte validated bool rcvdNonProbing bool @@ -23,7 +38,8 @@ type path struct { type pathManager struct { nextPathID pathID - paths map[pathID]*path + // ordered by lastPacketTime, with the most recently used path at the end + paths []*path getConnID func(pathID) (_ protocol.ConnectionID, ok bool) retireConnID func(pathID) @@ -37,7 +53,7 @@ func newPathManager( logger utils.Logger, ) *pathManager { return &pathManager{ - paths: make(map[pathID]*path), + paths: make([]*path, 0, maxPaths+1), getConnID: getConnID, retireConnID: retireConnID, logger: logger, @@ -46,47 +62,88 @@ func newPathManager( // Returns a path challenge frame if one should be sent. // May return nil. -func (pm *pathManager) HandlePacket(p receivedPacket, isNonProbing bool) (_ protocol.ConnectionID, _ ackhandler.Frame, shouldSwitch bool) { - for _, path := range pm.paths { - if addrsEqual(path.addr, p.remoteAddr) { +func (pm *pathManager) HandlePacket( + remoteAddr net.Addr, + t time.Time, + pathChallenge *wire.PathChallengeFrame, // may be nil if the packet didn't contain a PATH_CHALLENGE + isNonProbing bool, +) (_ protocol.ConnectionID, _ []ackhandler.Frame, shouldSwitch bool) { + var p *path + for i, path := range pm.paths { + if addrsEqual(path.addr, remoteAddr) { + p = path + p.lastPacketTime = t // already sent a PATH_CHALLENGE for this path if isNonProbing { path.rcvdNonProbing = true } if pm.logger.Debug() { - pm.logger.Debugf("received packet for path %s that was already probed, validated: %t", p.remoteAddr, path.validated) + pm.logger.Debugf("received packet for path %s that was already probed, validated: %t", remoteAddr, path.validated) + } + shouldSwitch = path.validated && path.rcvdNonProbing + if i != len(pm.paths)-1 { + // move the path to the end of the list + pm.paths = slices.Delete(pm.paths, i, i+1) + pm.paths = append(pm.paths, p) + } + if pathChallenge == nil { + return protocol.ConnectionID{}, nil, shouldSwitch } - return protocol.ConnectionID{}, ackhandler.Frame{}, path.validated && path.rcvdNonProbing } } if len(pm.paths) >= maxPaths { - if pm.logger.Debug() { - pm.logger.Debugf("received packet for previously unseen path %s, but already have %d paths", p.remoteAddr, len(pm.paths)) + if pm.paths[0].lastPacketTime.Add(pathTimeout).After(t) { + if pm.logger.Debug() { + pm.logger.Debugf("received packet for previously unseen path %s, but already have %d paths", remoteAddr, len(pm.paths)) + } + return protocol.ConnectionID{}, nil, shouldSwitch } - return protocol.ConnectionID{}, ackhandler.Frame{}, false + // evict the oldest path, if the last packet was received more than pathTimeout ago + pm.retireConnID(pm.paths[0].id) + pm.paths = pm.paths[1:] + } + + var pathID pathID + if p != nil { + pathID = p.id + } else { + pathID = pm.nextPathID } // previously unseen path, initiate path validation by sending a PATH_CHALLENGE - connID, ok := pm.getConnID(pm.nextPathID) + connID, ok := pm.getConnID(pathID) if !ok { - pm.logger.Debugf("skipping validation of new path %s since no connection ID is available", p.remoteAddr) - return protocol.ConnectionID{}, ackhandler.Frame{}, false + pm.logger.Debugf("skipping validation of new path %s since no connection ID is available", remoteAddr) + return protocol.ConnectionID{}, nil, shouldSwitch } - var b [8]byte - rand.Read(b[:]) - pm.paths[pm.nextPathID] = &path{ - addr: p.remoteAddr, - pathChallenge: b, - rcvdNonProbing: isNonProbing, + + frames := make([]ackhandler.Frame, 0, 2) + if p == nil { + var pathChallengeData [8]byte + rand.Read(pathChallengeData[:]) + p = &path{ + id: pm.nextPathID, + addr: remoteAddr, + lastPacketTime: t, + rcvdNonProbing: isNonProbing, + pathChallenge: pathChallengeData, + } + pm.nextPathID++ + pm.paths = append(pm.paths, p) + frames = append(frames, ackhandler.Frame{ + Frame: &wire.PathChallengeFrame{Data: p.pathChallenge}, + Handler: (*pathManagerAckHandler)(pm), + }) + pm.logger.Debugf("enqueueing PATH_CHALLENGE for new path %s", remoteAddr) } - pm.nextPathID++ - frame := ackhandler.Frame{ - Frame: &wire.PathChallengeFrame{Data: b}, - Handler: (*pathManagerAckHandler)(pm), + if pathChallenge != nil { + frames = append(frames, ackhandler.Frame{ + Frame: &wire.PathResponseFrame{Data: pathChallenge.Data}, + Handler: (*pathManagerAckHandler)(pm), + }) } - pm.logger.Debugf("enqueueing PATH_CHALLENGE for new path %s", p.remoteAddr) - return connID, frame, false + return connID, frames, shouldSwitch } func (pm *pathManager) HandlePathResponseFrame(f *wire.PathResponseFrame) { @@ -103,14 +160,15 @@ func (pm *pathManager) HandlePathResponseFrame(f *wire.PathResponseFrame) { // SwitchToPath is called when the connection switches to a new path func (pm *pathManager) SwitchToPath(addr net.Addr) { // retire all other paths - for id := range pm.paths { - if addrsEqual(pm.paths[id].addr, addr) { - pm.logger.Debugf("switching to path %d (%s)", id, addr) + for _, path := range pm.paths { + if addrsEqual(path.addr, addr) { + pm.logger.Debugf("switching to path %d (%s)", path.id, addr) continue } - pm.retireConnID(id) + pm.retireConnID(path.id) } clear(pm.paths) + pm.paths = pm.paths[:0] } type pathManagerAckHandler pathManager @@ -121,12 +179,14 @@ var _ ackhandler.FrameHandler = &pathManagerAckHandler{} func (pm *pathManagerAckHandler) OnAcked(f wire.Frame) {} func (pm *pathManagerAckHandler) OnLost(f wire.Frame) { - // TODO: retransmit the packet the first time it is lost - pc := f.(*wire.PathChallengeFrame) - for id, path := range pm.paths { + pc, ok := f.(*wire.PathChallengeFrame) + if !ok { + return + } + for i, path := range pm.paths { if path.pathChallenge == pc.Data { - delete(pm.paths, id) - pm.retireConnID(id) + pm.paths = slices.Delete(pm.paths, i, i+1) + pm.retireConnID(path.id) break } } diff --git a/vendor/github.com/quic-go/quic-go/path_manager_outgoing.go b/vendor/github.com/quic-go/quic-go/path_manager_outgoing.go new file mode 100644 index 0000000000..595eda237a --- /dev/null +++ b/vendor/github.com/quic-go/quic-go/path_manager_outgoing.go @@ -0,0 +1,311 @@ +package quic + +import ( + "context" + "crypto/rand" + "errors" + "slices" + "sync" + "sync/atomic" + "time" + + "github.com/quic-go/quic-go/internal/ackhandler" + "github.com/quic-go/quic-go/internal/protocol" + "github.com/quic-go/quic-go/internal/wire" +) + +var ( + // ErrPathClosed is returned when trying to switch to a path that has been closed. + ErrPathClosed = errors.New("path closed") + // ErrPathNotValidated is returned when trying to use a path before path probing has completed. + ErrPathNotValidated = errors.New("path not yet validated") +) + +var errPathDoesNotExist = errors.New("path does not exist") + +// Path is a network path. +type Path struct { + id pathID + pathManager *pathManagerOutgoing + tr *Transport + initialRTT time.Duration + + enablePath func() + validated atomic.Bool + abandon chan struct{} +} + +func (p *Path) Probe(ctx context.Context) error { + path := p.pathManager.addPath(p, p.enablePath) + + p.pathManager.enqueueProbe(p) + nextProbeDur := p.initialRTT + var timer *time.Timer + var timerChan <-chan time.Time + for { + select { + case <-ctx.Done(): + return context.Cause(ctx) + case <-path.Validated(): + p.validated.Store(true) + return nil + case <-timerChan: + p.pathManager.enqueueProbe(p) + case <-path.ProbeSent(): + case <-p.abandon: + return ErrPathClosed + } + + if timer != nil { + timer.Stop() + } + timer = time.NewTimer(nextProbeDur) + timerChan = timer.C + nextProbeDur *= 2 // exponential backoff + } +} + +// Switch switches the QUIC connection to this path. +// It immediately stops sending on the old path, and sends on this new path. +func (p *Path) Switch() error { + if err := p.pathManager.switchToPath(p.id); err != nil { + switch { + case errors.Is(err, ErrPathNotValidated): + return err + case errors.Is(err, errPathDoesNotExist) && !p.validated.Load(): + select { + case <-p.abandon: + return ErrPathClosed + default: + return ErrPathNotValidated + } + default: + return ErrPathClosed + } + } + return nil +} + +// Close abandons a path. +// It is not possible to close the path that’s currently active. +// After closing, it is not possible to probe this path again. +func (p *Path) Close() error { + select { + case <-p.abandon: + return nil + default: + } + + if err := p.pathManager.removePath(p.id); err != nil { + return err + } + close(p.abandon) + return nil +} + +type pathOutgoing struct { + pathChallenges [][8]byte // length is implicitly limited by exponential backoff + tr *Transport + isValidated bool + probeSent chan struct{} // receives when a PATH_CHALLENGE is sent + validated chan struct{} // closed when the path the corresponding PATH_RESPONSE is received + enablePath func() +} + +func (p *pathOutgoing) ProbeSent() <-chan struct{} { return p.probeSent } +func (p *pathOutgoing) Validated() <-chan struct{} { return p.validated } + +type pathManagerOutgoing struct { + getConnID func(pathID) (_ protocol.ConnectionID, ok bool) + retireConnID func(pathID) + scheduleSending func() + + mx sync.Mutex + activePath pathID + pathsToProbe []pathID + paths map[pathID]*pathOutgoing + nextPathID pathID + pathToSwitchTo *pathOutgoing +} + +func newPathManagerOutgoing( + getConnID func(pathID) (_ protocol.ConnectionID, ok bool), + retireConnID func(pathID), + scheduleSending func(), +) *pathManagerOutgoing { + return &pathManagerOutgoing{ + activePath: 0, // at initialization time, we're guaranteed to be using the handshake path + nextPathID: 1, + getConnID: getConnID, + retireConnID: retireConnID, + scheduleSending: scheduleSending, + paths: make(map[pathID]*pathOutgoing, 4), + } +} + +func (pm *pathManagerOutgoing) addPath(p *Path, enablePath func()) *pathOutgoing { + pm.mx.Lock() + defer pm.mx.Unlock() + + // path might already exist, and just being re-probed + if existingPath, ok := pm.paths[p.id]; ok { + existingPath.validated = make(chan struct{}) + return existingPath + } + + path := &pathOutgoing{ + tr: p.tr, + probeSent: make(chan struct{}, 1), + validated: make(chan struct{}), + enablePath: enablePath, + } + pm.paths[p.id] = path + return path +} + +func (pm *pathManagerOutgoing) enqueueProbe(p *Path) { + pm.mx.Lock() + pm.pathsToProbe = append(pm.pathsToProbe, p.id) + pm.mx.Unlock() + pm.scheduleSending() +} + +func (pm *pathManagerOutgoing) removePath(id pathID) error { + if err := pm.removePathImpl(id); err != nil { + return err + } + pm.scheduleSending() + return nil +} + +func (pm *pathManagerOutgoing) removePathImpl(id pathID) error { + pm.mx.Lock() + defer pm.mx.Unlock() + + if id == pm.activePath { + return errors.New("cannot close active path") + } + p, ok := pm.paths[id] + if !ok { + return nil + } + if len(p.pathChallenges) > 0 { + pm.retireConnID(id) + } + delete(pm.paths, id) + return nil +} + +func (pm *pathManagerOutgoing) switchToPath(id pathID) error { + pm.mx.Lock() + defer pm.mx.Unlock() + + p, ok := pm.paths[id] + if !ok { + return errPathDoesNotExist + } + if !p.isValidated { + return ErrPathNotValidated + } + pm.pathToSwitchTo = p + pm.activePath = id + return nil +} + +func (pm *pathManagerOutgoing) NewPath(t *Transport, initialRTT time.Duration, enablePath func()) *Path { + pm.mx.Lock() + defer pm.mx.Unlock() + + id := pm.nextPathID + pm.nextPathID++ + return &Path{ + pathManager: pm, + id: id, + tr: t, + enablePath: enablePath, + initialRTT: initialRTT, + abandon: make(chan struct{}), + } +} + +func (pm *pathManagerOutgoing) NextPathToProbe() (_ protocol.ConnectionID, _ ackhandler.Frame, _ *Transport, hasPath bool) { + pm.mx.Lock() + defer pm.mx.Unlock() + + var p *pathOutgoing + id := invalidPathID + for _, pID := range pm.pathsToProbe { + var ok bool + p, ok = pm.paths[pID] + if ok { + id = pID + break + } + // if the path doesn't exist in the map, it might have been abandoned + pm.pathsToProbe = pm.pathsToProbe[1:] + } + if id == invalidPathID { + return protocol.ConnectionID{}, ackhandler.Frame{}, nil, false + } + + connID, ok := pm.getConnID(id) + if !ok { + return protocol.ConnectionID{}, ackhandler.Frame{}, nil, false + } + + var b [8]byte + _, _ = rand.Read(b[:]) + p.pathChallenges = append(p.pathChallenges, b) + + pm.pathsToProbe = pm.pathsToProbe[1:] + p.enablePath() + select { + case p.probeSent <- struct{}{}: + default: + } + frame := ackhandler.Frame{ + Frame: &wire.PathChallengeFrame{Data: b}, + Handler: (*pathManagerOutgoingAckHandler)(pm), + } + return connID, frame, p.tr, true +} + +func (pm *pathManagerOutgoing) HandlePathResponseFrame(f *wire.PathResponseFrame) { + pm.mx.Lock() + defer pm.mx.Unlock() + + for _, p := range pm.paths { + if slices.Contains(p.pathChallenges, f.Data) { + // path validated + if !p.isValidated { + // make sure that duplicate PATH_RESPONSE frames are ignored + p.isValidated = true + p.pathChallenges = nil + close(p.validated) + } + break + } + } +} + +func (pm *pathManagerOutgoing) ShouldSwitchPath() (*Transport, bool) { + pm.mx.Lock() + defer pm.mx.Unlock() + + if pm.pathToSwitchTo == nil { + return nil, false + } + p := pm.pathToSwitchTo + pm.pathToSwitchTo = nil + return p.tr, true +} + +type pathManagerOutgoingAckHandler pathManagerOutgoing + +var _ ackhandler.FrameHandler = &pathManagerOutgoingAckHandler{} + +// OnAcked is called when the PATH_CHALLENGE is acked. +// This doesn't validate the path, only receiving the PATH_RESPONSE does. +func (pm *pathManagerOutgoingAckHandler) OnAcked(wire.Frame) {} + +func (pm *pathManagerOutgoingAckHandler) OnLost(wire.Frame) {} diff --git a/vendor/github.com/quic-go/quic-go/quicvarint/io.go b/vendor/github.com/quic-go/quic-go/quicvarint/io.go index 9368d1c58b..27def40929 100644 --- a/vendor/github.com/quic-go/quic-go/quicvarint/io.go +++ b/vendor/github.com/quic-go/quic-go/quicvarint/io.go @@ -31,7 +31,7 @@ func NewReader(r io.Reader) Reader { func (r *byteReader) ReadByte() (byte, error) { var b [1]byte - n, err := r.Reader.Read(b[:]) + n, err := r.Read(b[:]) if n == 1 && err == io.EOF { err = nil } @@ -63,6 +63,6 @@ func NewWriter(w io.Writer) Writer { } func (w *byteWriter) WriteByte(c byte) error { - _, err := w.Writer.Write([]byte{c}) + _, err := w.Write([]byte{c}) return err } diff --git a/vendor/github.com/quic-go/quic-go/quicvarint/varint.go b/vendor/github.com/quic-go/quic-go/quicvarint/varint.go index 9a22e334f3..f095e29897 100644 --- a/vendor/github.com/quic-go/quic-go/quicvarint/varint.go +++ b/vendor/github.com/quic-go/quic-go/quicvarint/varint.go @@ -125,17 +125,18 @@ func AppendWithLen(b []byte, i uint64, length int) []byte { if l > length { panic(fmt.Sprintf("cannot encode %d in %d bytes", i, length)) } - if length == 2 { + switch length { + case 2: b = append(b, 0b01000000) - } else if length == 4 { + case 4: b = append(b, 0b10000000) - } else if length == 8 { + case 8: b = append(b, 0b11000000) } - for j := 1; j < length-l; j++ { + for range length - l - 1 { b = append(b, 0) } - for j := 0; j < l; j++ { + for j := range l { b = append(b, uint8(i>>(8*(l-1-j)))) } return b diff --git a/vendor/github.com/quic-go/quic-go/retransmission_queue.go b/vendor/github.com/quic-go/quic-go/retransmission_queue.go index 14ae1e3b88..323af5b0c4 100644 --- a/vendor/github.com/quic-go/quic-go/retransmission_queue.go +++ b/vendor/github.com/quic-go/quic-go/retransmission_queue.go @@ -9,126 +9,106 @@ import ( "github.com/quic-go/quic-go/internal/wire" ) -type retransmissionQueue struct { - initial []wire.Frame - initialCryptoData []*wire.CryptoFrame - - handshake []wire.Frame - handshakeCryptoData []*wire.CryptoFrame - - appData []wire.Frame +type framesToRetransmit struct { + crypto []*wire.CryptoFrame + other []wire.Frame } -func newRetransmissionQueue() *retransmissionQueue { - return &retransmissionQueue{} +type retransmissionQueue struct { + initial *framesToRetransmit + handshake *framesToRetransmit + appData framesToRetransmit } -// AddPing queues a ping. -// It is used when a probe packet needs to be sent -func (q *retransmissionQueue) AddPing(encLevel protocol.EncryptionLevel) { - //nolint:exhaustive // Cannot send probe packets for 0-RTT. - switch encLevel { - case protocol.EncryptionInitial: - q.addInitial(&wire.PingFrame{}) - case protocol.EncryptionHandshake: - q.addHandshake(&wire.PingFrame{}) - case protocol.Encryption1RTT: - q.addAppData(&wire.PingFrame{}) - default: - panic("unexpected encryption level") +func newRetransmissionQueue() *retransmissionQueue { + return &retransmissionQueue{ + initial: &framesToRetransmit{}, + handshake: &framesToRetransmit{}, } } func (q *retransmissionQueue) addInitial(f wire.Frame) { + if q.initial == nil { + return + } if cf, ok := f.(*wire.CryptoFrame); ok { - q.initialCryptoData = append(q.initialCryptoData, cf) + q.initial.crypto = append(q.initial.crypto, cf) return } - q.initial = append(q.initial, f) + q.initial.other = append(q.initial.other, f) } func (q *retransmissionQueue) addHandshake(f wire.Frame) { + if q.handshake == nil { + return + } if cf, ok := f.(*wire.CryptoFrame); ok { - q.handshakeCryptoData = append(q.handshakeCryptoData, cf) + q.handshake.crypto = append(q.handshake.crypto, cf) return } - q.handshake = append(q.handshake, f) -} - -func (q *retransmissionQueue) HasInitialData() bool { - return len(q.initialCryptoData) > 0 || len(q.initial) > 0 -} - -func (q *retransmissionQueue) HasHandshakeData() bool { - return len(q.handshakeCryptoData) > 0 || len(q.handshake) > 0 -} - -func (q *retransmissionQueue) HasAppData() bool { - return len(q.appData) > 0 + q.handshake.other = append(q.handshake.other, f) } func (q *retransmissionQueue) addAppData(f wire.Frame) { - if _, ok := f.(*wire.StreamFrame); ok { + switch f := f.(type) { + case *wire.StreamFrame: panic("STREAM frames are handled with their respective streams.") + case *wire.CryptoFrame: + q.appData.crypto = append(q.appData.crypto, f) + default: + q.appData.other = append(q.appData.other, f) } - q.appData = append(q.appData, f) } -func (q *retransmissionQueue) GetInitialFrame(maxLen protocol.ByteCount, v protocol.Version) wire.Frame { - if len(q.initialCryptoData) > 0 { - f := q.initialCryptoData[0] - newFrame, needsSplit := f.MaybeSplitOffFrame(maxLen, v) - if newFrame == nil && !needsSplit { // the whole frame fits - q.initialCryptoData = q.initialCryptoData[1:] - return f - } - if newFrame != nil { // frame was split. Leave the original frame in the queue. - return newFrame - } +func (q *retransmissionQueue) HasData(encLevel protocol.EncryptionLevel) bool { + //nolint:exhaustive // 0-RTT data is retransmitted in 1-RTT packets. + switch encLevel { + case protocol.EncryptionInitial: + return q.initial != nil && + (len(q.initial.crypto) > 0 || len(q.initial.other) > 0) + case protocol.EncryptionHandshake: + return q.handshake != nil && + (len(q.handshake.crypto) > 0 || len(q.handshake.other) > 0) + case protocol.Encryption1RTT: + return len(q.appData.crypto) > 0 || len(q.appData.other) > 0 } - if len(q.initial) == 0 { - return nil + return false +} + +func (q *retransmissionQueue) GetFrame(encLevel protocol.EncryptionLevel, maxLen protocol.ByteCount, v protocol.Version) wire.Frame { + var r *framesToRetransmit + //nolint:exhaustive // 0-RTT data is retransmitted in 1-RTT packets. + switch encLevel { + case protocol.EncryptionInitial: + r = q.initial + case protocol.EncryptionHandshake: + r = q.handshake + case protocol.Encryption1RTT: + r = &q.appData } - f := q.initial[0] - if f.Length(v) > maxLen { + if r == nil { return nil } - q.initial = q.initial[1:] - return f -} -func (q *retransmissionQueue) GetHandshakeFrame(maxLen protocol.ByteCount, v protocol.Version) wire.Frame { - if len(q.handshakeCryptoData) > 0 { - f := q.handshakeCryptoData[0] + if len(r.crypto) > 0 { + f := r.crypto[0] newFrame, needsSplit := f.MaybeSplitOffFrame(maxLen, v) if newFrame == nil && !needsSplit { // the whole frame fits - q.handshakeCryptoData = q.handshakeCryptoData[1:] + r.crypto = r.crypto[1:] return f } if newFrame != nil { // frame was split. Leave the original frame in the queue. return newFrame } } - if len(q.handshake) == 0 { + if len(r.other) == 0 { return nil } - f := q.handshake[0] + f := r.other[0] if f.Length(v) > maxLen { return nil } - q.handshake = q.handshake[1:] - return f -} - -func (q *retransmissionQueue) GetAppDataFrame(maxLen protocol.ByteCount, v protocol.Version) wire.Frame { - if len(q.appData) == 0 { - return nil - } - f := q.appData[0] - if f.Length(v) > maxLen { - return nil - } - q.appData = q.appData[1:] + r.other = r.other[1:] return f } @@ -137,25 +117,23 @@ func (q *retransmissionQueue) DropPackets(encLevel protocol.EncryptionLevel) { switch encLevel { case protocol.EncryptionInitial: q.initial = nil - q.initialCryptoData = nil case protocol.EncryptionHandshake: q.handshake = nil - q.handshakeCryptoData = nil default: panic(fmt.Sprintf("unexpected encryption level: %s", encLevel)) } } -func (q *retransmissionQueue) InitialAckHandler() ackhandler.FrameHandler { - return (*retransmissionQueueInitialAckHandler)(q) -} - -func (q *retransmissionQueue) HandshakeAckHandler() ackhandler.FrameHandler { - return (*retransmissionQueueHandshakeAckHandler)(q) -} - -func (q *retransmissionQueue) AppDataAckHandler() ackhandler.FrameHandler { - return (*retransmissionQueueAppDataAckHandler)(q) +func (q *retransmissionQueue) AckHandler(encLevel protocol.EncryptionLevel) ackhandler.FrameHandler { + switch encLevel { + case protocol.EncryptionInitial: + return (*retransmissionQueueInitialAckHandler)(q) + case protocol.EncryptionHandshake: + return (*retransmissionQueueHandshakeAckHandler)(q) + case protocol.Encryption0RTT, protocol.Encryption1RTT: + return (*retransmissionQueueAppDataAckHandler)(q) + } + return nil } type retransmissionQueueInitialAckHandler retransmissionQueue diff --git a/vendor/github.com/quic-go/quic-go/server.go b/vendor/github.com/quic-go/quic-go/server.go index 2bb821ab73..3eb8e1d431 100644 --- a/vendor/github.com/quic-go/quic-go/server.go +++ b/vendor/github.com/quic-go/quic-go/server.go @@ -17,7 +17,7 @@ import ( "github.com/quic-go/quic-go/logging" ) -// ErrServerClosed is returned by the Listener or EarlyListener's Accept method after a call to Close. +// ErrServerClosed is returned by the [Listener] or [EarlyListener]'s Accept method after a call to Close. var ErrServerClosed = errServerClosed{} type errServerClosed struct{} @@ -61,6 +61,7 @@ type rejectedPacket struct { // A Listener of QUIC type baseServer struct { + tr *Transport disableVersionNegotiation bool acceptEarlyConns bool @@ -74,7 +75,6 @@ type baseServer struct { connIDGenerator ConnectionIDGenerator statelessResetter *statelessResetter - connHandler packetHandlerManager onClose func() receivedPackets chan receivedPacket @@ -89,7 +89,7 @@ type baseServer struct { context.Context, context.CancelCauseFunc, sendConn, - connRunner, + *Transport, protocol.ConnectionID, /* original dest connection ID */ *protocol.ConnectionID, /* retry src connection ID */ protocol.ConnectionID, /* client dest connection ID */ @@ -146,11 +146,11 @@ func (l *Listener) Accept(ctx context.Context) (Connection, error) { } // Close closes the listener. -// Accept will return ErrServerClosed as soon as all connections in the accept queue have been accepted. +// Accept will return [ErrServerClosed] as soon as all connections in the accept queue have been accepted. // QUIC handshakes that are still in flight will be rejected with a CONNECTION_REFUSED error. // The effect of closing the listener depends on how it was created: -// * if it was created using Transport.Listen, already established connections will be unaffected -// * if it was created using the Listen convenience method, all established connection will be closed immediately +// - if it was created using [Transport.Listen], already established connections will be unaffected +// - if it was created using the [Listen] convenience method, all established connection will be closed immediately func (l *Listener) Close() error { return l.baseServer.Close() } @@ -186,7 +186,7 @@ func (l *EarlyListener) Addr() net.Addr { } // ListenAddr creates a QUIC server listening on a given address. -// See Listen for more details. +// See [Listen] for more details. func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (*Listener, error) { conn, err := listenUDP(addr) if err != nil { @@ -199,7 +199,7 @@ func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (*Listener, er }).Listen(tlsConf, config) } -// ListenAddrEarly works like ListenAddr, but it returns connections before the handshake completes. +// ListenAddrEarly works like [ListenAddr], but it returns connections before the handshake completes. func ListenAddrEarly(addr string, tlsConf *tls.Config, config *Config) (*EarlyListener, error) { conn, err := listenUDP(addr) if err != nil { @@ -221,16 +221,16 @@ func listenUDP(addr string) (*net.UDPConn, error) { } // Listen listens for QUIC connections on a given net.PacketConn. -// If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does), +// If the PacketConn satisfies the [OOBCapablePacketConn] interface (as a [net.UDPConn] does), // ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP // will be used instead of ReadFrom and WriteTo to read/write packets. // A single net.PacketConn can only be used for a single call to Listen. // // The tls.Config must not be nil and must contain a certificate configuration. -// Furthermore, it must define an application control (using NextProtos). +// Furthermore, it must define an application control (using [NextProtos]). // The quic.Config may be nil, in that case the default values will be used. // -// This is a convenience function. More advanced use cases should instantiate a Transport, +// This is a convenience function. More advanced use cases should instantiate a [Transport], // which offers configuration options for a more fine-grained control of the connection establishment, // including reusing the underlying UDP socket for outgoing QUIC connections. // When closing a listener created with Listen, all established QUIC connections will be closed immediately. @@ -239,7 +239,7 @@ func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Listener return tr.Listen(tlsConf, config) } -// ListenEarly works like Listen, but it returns connections before the handshake completes. +// ListenEarly works like [Listen], but it returns connections before the handshake completes. func ListenEarly(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*EarlyListener, error) { tr := &Transport{Conn: conn, isSingleUse: true} return tr.ListenEarly(tlsConf, config) @@ -247,7 +247,7 @@ func ListenEarly(conn net.PacketConn, tlsConf *tls.Config, config *Config) (*Ear func newServer( conn rawConn, - connHandler packetHandlerManager, + tr *Transport, connIDGenerator ConnectionIDGenerator, statelessResetter *statelessResetter, connContext func(context.Context) context.Context, @@ -264,6 +264,7 @@ func newServer( s := &baseServer{ conn: conn, connContext: connContext, + tr: tr, tlsConf: tlsConf, config: config, tokenGenerator: handshake.NewTokenGenerator(tokenGeneratorKey), @@ -271,7 +272,6 @@ func newServer( verifySourceAddress: verifySourceAddress, connIDGenerator: connIDGenerator, statelessResetter: statelessResetter, - connHandler: connHandler, connQueue: make(chan quicConn, protocol.MaxAcceptQueueSize), errorChan: make(chan struct{}), stopAccepting: make(chan struct{}), @@ -426,6 +426,9 @@ func (s *baseServer) handlePacketImpl(p receivedPacket) bool /* is the buffer st // send a Version Negotiation Packet if the client is speaking a different protocol version if !protocol.IsSupportedVersion(s.config.Versions, v) { if s.disableVersionNegotiation { + if s.tracer != nil && s.tracer.DroppedPacket != nil { + s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropUnexpectedVersion) + } return false } @@ -498,7 +501,7 @@ func (s *baseServer) handle0RTTPacket(p receivedPacket) bool { } // check again if we might have a connection now - if handler, ok := s.connHandler.Get(connID); ok { + if handler, ok := s.tr.connRunner().Get(connID); ok { handler.handlePacket(p) return true } @@ -588,7 +591,7 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error // The server queues packets for a while, and we might already have established a connection by now. // This results in a second check in the connection map. // That's ok since it's not the hot path (it's only taken by some Initial and 0-RTT packets). - if handler, ok := s.connHandler.Get(hdr.DestConnectionID); ok { + if handler, ok := s.tr.connRunner().Get(hdr.DestConnectionID); ok { handler.handlePacket(p) return nil } @@ -646,7 +649,7 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error config := s.config if s.config.GetConfigForClient != nil { - conf, err := s.config.GetConfigForClient(&ClientHelloInfo{ + conf, err := s.config.GetConfigForClient(&ClientInfo{ RemoteAddr: p.remoteAddr, AddrVerified: clientAddrVerified, }) @@ -703,7 +706,7 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error ctx, cancel, newSendConn(s.conn, p.remoteAddr, p.info, s.logger), - s.connHandler, + s.tr, origDestConnID, retrySrcConnID, hdr.DestConnectionID, @@ -724,7 +727,7 @@ func (s *baseServer) handleInitialImpl(p receivedPacket, hdr *wire.Header) error // This is very unlikely: Even if an attacker chooses a connection ID that's already in use, // under normal circumstances the packet would just be routed to that connection. // The only time this collision will occur if we receive the two Initial packets at the same time. - if added := s.connHandler.AddWithConnID(hdr.DestConnectionID, connID, conn); !added { + if added := s.tr.connRunner().AddWithConnID(hdr.DestConnectionID, connID, conn); !added { delete(s.zeroRTTQueues, hdr.DestConnectionID) conn.closeWithTransportError(qerr.ConnectionRefused) return nil diff --git a/vendor/github.com/quic-go/quic-go/streams_map.go b/vendor/github.com/quic-go/quic-go/streams_map.go index 0ce91287b7..510b3e5919 100644 --- a/vendor/github.com/quic-go/quic-go/streams_map.go +++ b/vendor/github.com/quic-go/quic-go/streams_map.go @@ -2,9 +2,7 @@ package quic import ( "context" - "errors" "fmt" - "net" "sync" "github.com/quic-go/quic-go/internal/flowcontrol" @@ -34,19 +32,6 @@ func convertStreamError(err error, stype protocol.StreamType, pers protocol.Pers return fmt.Errorf(strError.Error(), ids...) } -type streamOpenErr struct{ error } - -var _ net.Error = &streamOpenErr{} - -func (streamOpenErr) Timeout() bool { return false } -func (e streamOpenErr) Unwrap() error { return e.error } - -func (e streamOpenErr) Temporary() bool { - // In older versions of quic-go, the stream limit error was documented to be a net.Error.Temporary. - // This function was since deprecated, but we keep the existing behavior. - return errors.Is(e, &StreamLimitReachedError{}) -} - // StreamLimitReachedError is returned from Connection.OpenStream and Connection.OpenUniStream // when it is not possible to open a new stream because the number of opens streams reached // the peer's stream limit. diff --git a/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go b/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go index a8d04b04f9..d4c1825929 100644 --- a/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go +++ b/vendor/github.com/quic-go/quic-go/streams_map_outgoing.go @@ -2,6 +2,7 @@ package quic import ( "context" + "slices" "sync" "github.com/quic-go/quic-go/internal/protocol" @@ -19,9 +20,7 @@ type outgoingStreamsMap[T outgoingStream] struct { streamType protocol.StreamType streams map[protocol.StreamNum]T - openQueue map[uint64]chan struct{} - lowestInQueue uint64 - highestInQueue uint64 + openQueue []chan struct{} nextStream protocol.StreamNum // stream ID of the stream returned by OpenStream(Sync) maxStream protocol.StreamNum // the maximum stream ID we're allowed to open @@ -41,7 +40,6 @@ func newOutgoingStreamsMap[T outgoingStream]( return &outgoingStreamsMap[T]{ streamType: streamType, streams: make(map[protocol.StreamNum]T), - openQueue: make(map[uint64]chan struct{}), maxStream: protocol.InvalidStreamNum, nextStream: 1, newStream: newStream, @@ -60,7 +58,7 @@ func (m *outgoingStreamsMap[T]) OpenStream() (T, error) { // if there are OpenStreamSync calls waiting, return an error here if len(m.openQueue) > 0 || m.nextStream > m.maxStream { m.maybeSendBlockedFrame() - return *new(T), streamOpenErr{&StreamLimitReachedError{}} + return *new(T), &StreamLimitReachedError{} } return m.openStream(), nil } @@ -72,22 +70,15 @@ func (m *outgoingStreamsMap[T]) OpenStreamSync(ctx context.Context) (T, error) { if m.closeErr != nil { return *new(T), m.closeErr } - if err := ctx.Err(); err != nil { return *new(T), err } - if len(m.openQueue) == 0 && m.nextStream <= m.maxStream { return m.openStream(), nil } waitChan := make(chan struct{}, 1) - queuePos := m.highestInQueue - m.highestInQueue++ - if len(m.openQueue) == 0 { - m.lowestInQueue = queuePos - } - m.openQueue[queuePos] = waitChan + m.openQueue = append(m.openQueue, waitChan) m.maybeSendBlockedFrame() for { @@ -95,12 +86,17 @@ func (m *outgoingStreamsMap[T]) OpenStreamSync(ctx context.Context) (T, error) { select { case <-ctx.Done(): m.mutex.Lock() - delete(m.openQueue, queuePos) + m.openQueue = slices.DeleteFunc(m.openQueue, func(c chan struct{}) bool { + return c == waitChan + }) + // If we just received a MAX_STREAMS frame, this might have been the next stream + // that could be opened. Make sure we unblock the next OpenStreamSync call. + m.maybeUnblockOpenSync() return *new(T), ctx.Err() case <-waitChan: } - m.mutex.Lock() + m.mutex.Lock() if m.closeErr != nil { return *new(T), m.closeErr } @@ -109,9 +105,8 @@ func (m *outgoingStreamsMap[T]) OpenStreamSync(ctx context.Context) (T, error) { continue } str := m.openStream() - delete(m.openQueue, queuePos) - m.lowestInQueue = queuePos + 1 - m.unblockOpenSync() + m.openQueue = m.openQueue[1:] + m.maybeUnblockOpenSync() return str, nil } } @@ -181,7 +176,7 @@ func (m *outgoingStreamsMap[T]) SetMaxStream(num protocol.StreamNum) { if m.maxStream < m.nextStream-1+protocol.StreamNum(len(m.openQueue)) { m.maybeSendBlockedFrame() } - m.unblockOpenSync() + m.maybeUnblockOpenSync() } // UpdateSendWindow is called when the peer's transport parameters are received. @@ -196,27 +191,25 @@ func (m *outgoingStreamsMap[T]) UpdateSendWindow(limit protocol.ByteCount) { } // unblockOpenSync unblocks the next OpenStreamSync go-routine to open a new stream -func (m *outgoingStreamsMap[T]) unblockOpenSync() { +func (m *outgoingStreamsMap[T]) maybeUnblockOpenSync() { if len(m.openQueue) == 0 { return } - for qp := m.lowestInQueue; qp <= m.highestInQueue; qp++ { - c, ok := m.openQueue[qp] - if !ok { // entry was deleted because the context was canceled - continue - } - // unblockOpenSync is called both from OpenStreamSync and from SetMaxStream. - // It's sufficient to only unblock OpenStreamSync once. - select { - case c <- struct{}{}: - default: - } + if m.nextStream > m.maxStream { return } + // unblockOpenSync is called both from OpenStreamSync and from SetMaxStream. + // It's sufficient to only unblock OpenStreamSync once. + select { + case m.openQueue[0] <- struct{}{}: + default: + } } func (m *outgoingStreamsMap[T]) CloseWithError(err error) { m.mutex.Lock() + defer m.mutex.Unlock() + m.closeErr = err for _, str := range m.streams { str.closeForShutdown(err) @@ -226,5 +219,5 @@ func (m *outgoingStreamsMap[T]) CloseWithError(err error) { close(c) } } - m.mutex.Unlock() + m.openQueue = nil } diff --git a/vendor/github.com/quic-go/quic-go/sys_conn.go b/vendor/github.com/quic-go/quic-go/sys_conn.go index 811131d944..8159a1469c 100644 --- a/vendor/github.com/quic-go/quic-go/sys_conn.go +++ b/vendor/github.com/quic-go/quic-go/sys_conn.go @@ -14,7 +14,7 @@ import ( ) // OOBCapablePacketConn is a connection that allows the reading of ECN bits from the IP header. -// If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will use it. +// If the PacketConn passed to the [Transport] satisfies this interface, quic-go will use it. // In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets. type OOBCapablePacketConn interface { net.PacketConn @@ -92,7 +92,7 @@ func (c *basicConn) ReadPacket() (receivedPacket, error) { // The packet size should not exceed protocol.MaxPacketBufferSize bytes // If it does, we only read a truncated packet, which will then end up undecryptable buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize] - n, addr, err := c.PacketConn.ReadFrom(buffer.Data) + n, addr, err := c.ReadFrom(buffer.Data) if err != nil { return receivedPacket{}, err } @@ -111,7 +111,7 @@ func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte, gsoSize uint1 if ecn != protocol.ECNUnsupported { panic("cannot use ECN with a basicConn") } - return c.PacketConn.WriteTo(b, addr) + return c.WriteTo(b, addr) } func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} } diff --git a/vendor/github.com/quic-go/quic-go/sys_conn_oob.go b/vendor/github.com/quic-go/quic-go/sys_conn_oob.go index 7597968203..5ed1b656e7 100644 --- a/vendor/github.com/quic-go/quic-go/sys_conn_oob.go +++ b/vendor/github.com/quic-go/quic-go/sys_conn_oob.go @@ -257,7 +257,7 @@ func (c *oobConn) WritePacket(b []byte, addr net.Addr, packetInfoOOB []byte, gso } } } - n, _, err := c.OOBCapablePacketConn.WriteMsgUDP(b, oob, addr.(*net.UDPAddr)) + n, _, err := c.WriteMsgUDP(b, oob, addr.(*net.UDPAddr)) return n, err } diff --git a/vendor/github.com/quic-go/quic-go/transport.go b/vendor/github.com/quic-go/quic-go/transport.go index 41dbc7ab05..a7775fb147 100644 --- a/vendor/github.com/quic-go/quic-go/transport.go +++ b/vendor/github.com/quic-go/quic-go/transport.go @@ -17,7 +17,7 @@ import ( "github.com/quic-go/quic-go/logging" ) -// ErrTransportClosed is returned by the Transport's Listen or Dial method after it was closed. +// ErrTransportClosed is returned by the [Transport]'s Listen or Dial method after it was closed. var ErrTransportClosed = &errTransportClosed{} type errTransportClosed struct { @@ -38,6 +38,10 @@ func (e *errTransportClosed) Is(target error) bool { return ok } +type transportID uint64 + +var transportIDCounter atomic.Uint64 + var errListenerAlreadySet = errors.New("listener already set") // The Transport is the central point to manage incoming and outgoing QUIC connections. @@ -45,7 +49,7 @@ var errListenerAlreadySet = errors.New("listener already set") // This means that a single UDP socket can be used for listening for incoming connections, as well as // for dialing an arbitrary number of outgoing connections. // A Transport handles a single net.PacketConn, and offers a range of configuration options -// compared to the simple helper functions like Listen and Dial that this package provides. +// compared to the simple helper functions like [Listen] and [Dial] that this package provides. type Transport struct { // A single net.PacketConn can only be handled by one Transport. // Bad things will happen if passed to multiple Transports. @@ -133,6 +137,7 @@ type Transport struct { initErr error // Set in init. + transportID transportID // If no ConnectionIDGenerator is set, this is the ConnectionIDLength. connIDLen int // Set in init. @@ -160,7 +165,7 @@ type Transport struct { // Listen starts listening for incoming QUIC connections. // There can only be a single listener on any net.PacketConn. -// Listen may only be called again after the current Listener was closed. +// Listen may only be called again after the current listener was closed. func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) { s, err := t.createServer(tlsConf, conf, false) if err != nil { @@ -171,7 +176,7 @@ func (t *Transport) Listen(tlsConf *tls.Config, conf *Config) (*Listener, error) // ListenEarly starts listening for incoming QUIC connections. // There can only be a single listener on any net.PacketConn. -// Listen may only be called again after the current Listener was closed. +// ListenEarly may only be called again after the current listener was closed. func (t *Transport) ListenEarly(tlsConf *tls.Config, conf *Config) (*EarlyListener, error) { s, err := t.createServer(tlsConf, conf, true) if err != nil { @@ -207,7 +212,7 @@ func (t *Transport) createServer(tlsConf *tls.Config, conf *Config, allow0RTT bo } s := newServer( t.conn, - t.handlerMap, + t, t.connIDGenerator, t.statelessResetter, t.ConnContext, @@ -298,7 +303,7 @@ func (t *Transport) doDial( conn := newClientConnection( context.WithoutCancel(ctx), sendConn, - t.handlerMap, + t, destConnID, srcConnID, t.connIDGenerator, @@ -371,6 +376,7 @@ func (t *Transport) doDial( func (t *Transport) init(allowZeroLengthConnIDs bool) error { t.initOnce.Do(func() { + t.transportID = transportID(transportIDCounter.Add(1)) var conn rawConn if c, ok := t.Conn.(rawConn); ok { conn = c @@ -420,6 +426,12 @@ func (t *Transport) init(allowZeroLengthConnIDs bool) error { return t.initErr } +func (t *Transport) connRunner() packetHandlerManager { + return t.handlerMap +} + +func (t *Transport) id() transportID { return t.transportID } + // WriteTo sends a packet on the underlying connection. func (t *Transport) WriteTo(b []byte, addr net.Addr) (int, error) { if err := t.init(false); err != nil { diff --git a/vendor/golang.org/x/exp/LICENSE b/vendor/golang.org/x/exp/LICENSE deleted file mode 100644 index 6a66aea5ea..0000000000 --- a/vendor/golang.org/x/exp/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2009 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/golang.org/x/exp/PATENTS b/vendor/golang.org/x/exp/PATENTS deleted file mode 100644 index 733099041f..0000000000 --- a/vendor/golang.org/x/exp/PATENTS +++ /dev/null @@ -1,22 +0,0 @@ -Additional IP Rights Grant (Patents) - -"This implementation" means the copyrightable works distributed by -Google as part of the Go project. - -Google hereby grants to You a perpetual, worldwide, non-exclusive, -no-charge, royalty-free, irrevocable (except as stated in this section) -patent license to make, have made, use, offer to sell, sell, import, -transfer and otherwise run, modify and propagate the contents of this -implementation of Go, where such license applies only to those patent -claims, both currently owned or controlled by Google and acquired in -the future, licensable by Google that are necessarily infringed by this -implementation of Go. This grant does not include claims that would be -infringed only as a consequence of further modification of this -implementation. If you or your agent or exclusive licensee institute or -order or agree to the institution of patent litigation against any -entity (including a cross-claim or counterclaim in a lawsuit) alleging -that this implementation of Go or any code incorporated within this -implementation of Go constitutes direct or contributory patent -infringement, or inducement of patent infringement, then any patent -rights granted to you under this License for this implementation of Go -shall terminate as of the date such litigation is filed. diff --git a/vendor/golang.org/x/exp/rand/exp.go b/vendor/golang.org/x/exp/rand/exp.go deleted file mode 100644 index 0838672767..0000000000 --- a/vendor/golang.org/x/exp/rand/exp.go +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rand - -import ( - "math" -) - -/* - * Exponential distribution - * - * See "The Ziggurat Method for Generating Random Variables" - * (Marsaglia & Tsang, 2000) - * http://www.jstatsoft.org/v05/i08/paper [pdf] - */ - -const ( - re = 7.69711747013104972 -) - -// ExpFloat64 returns an exponentially distributed float64 in the range -// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter -// (lambda) is 1 and whose mean is 1/lambda (1). -// To produce a distribution with a different rate parameter, -// callers can adjust the output using: -// -// sample = ExpFloat64() / desiredRateParameter -func (r *Rand) ExpFloat64() float64 { - for { - j := r.Uint32() - i := j & 0xFF - x := float64(j) * float64(we[i]) - if j < ke[i] { - return x - } - if i == 0 { - return re - math.Log(r.Float64()) - } - if fe[i]+float32(r.Float64())*(fe[i-1]-fe[i]) < float32(math.Exp(-x)) { - return x - } - } -} - -var ke = [256]uint32{ - 0xe290a139, 0x0, 0x9beadebc, 0xc377ac71, 0xd4ddb990, - 0xde893fb8, 0xe4a8e87c, 0xe8dff16a, 0xebf2deab, 0xee49a6e8, - 0xf0204efd, 0xf19bdb8e, 0xf2d458bb, 0xf3da104b, 0xf4b86d78, - 0xf577ad8a, 0xf61de83d, 0xf6afb784, 0xf730a573, 0xf7a37651, - 0xf80a5bb6, 0xf867189d, 0xf8bb1b4f, 0xf9079062, 0xf94d70ca, - 0xf98d8c7d, 0xf9c8928a, 0xf9ff175b, 0xfa319996, 0xfa6085f8, - 0xfa8c3a62, 0xfab5084e, 0xfadb36c8, 0xfaff0410, 0xfb20a6ea, - 0xfb404fb4, 0xfb5e2951, 0xfb7a59e9, 0xfb95038c, 0xfbae44ba, - 0xfbc638d8, 0xfbdcf892, 0xfbf29a30, 0xfc0731df, 0xfc1ad1ed, - 0xfc2d8b02, 0xfc3f6c4d, 0xfc5083ac, 0xfc60ddd1, 0xfc708662, - 0xfc7f8810, 0xfc8decb4, 0xfc9bbd62, 0xfca9027c, 0xfcb5c3c3, - 0xfcc20864, 0xfccdd70a, 0xfcd935e3, 0xfce42ab0, 0xfceebace, - 0xfcf8eb3b, 0xfd02c0a0, 0xfd0c3f59, 0xfd156b7b, 0xfd1e48d6, - 0xfd26daff, 0xfd2f2552, 0xfd372af7, 0xfd3eeee5, 0xfd4673e7, - 0xfd4dbc9e, 0xfd54cb85, 0xfd5ba2f2, 0xfd62451b, 0xfd68b415, - 0xfd6ef1da, 0xfd750047, 0xfd7ae120, 0xfd809612, 0xfd8620b4, - 0xfd8b8285, 0xfd90bcf5, 0xfd95d15e, 0xfd9ac10b, 0xfd9f8d36, - 0xfda43708, 0xfda8bf9e, 0xfdad2806, 0xfdb17141, 0xfdb59c46, - 0xfdb9a9fd, 0xfdbd9b46, 0xfdc170f6, 0xfdc52bd8, 0xfdc8ccac, - 0xfdcc542d, 0xfdcfc30b, 0xfdd319ef, 0xfdd6597a, 0xfdd98245, - 0xfddc94e5, 0xfddf91e6, 0xfde279ce, 0xfde54d1f, 0xfde80c52, - 0xfdeab7de, 0xfded5034, 0xfdefd5be, 0xfdf248e3, 0xfdf4aa06, - 0xfdf6f984, 0xfdf937b6, 0xfdfb64f4, 0xfdfd818d, 0xfdff8dd0, - 0xfe018a08, 0xfe03767a, 0xfe05536c, 0xfe07211c, 0xfe08dfc9, - 0xfe0a8fab, 0xfe0c30fb, 0xfe0dc3ec, 0xfe0f48b1, 0xfe10bf76, - 0xfe122869, 0xfe1383b4, 0xfe14d17c, 0xfe1611e7, 0xfe174516, - 0xfe186b2a, 0xfe19843e, 0xfe1a9070, 0xfe1b8fd6, 0xfe1c8289, - 0xfe1d689b, 0xfe1e4220, 0xfe1f0f26, 0xfe1fcfbc, 0xfe2083ed, - 0xfe212bc3, 0xfe21c745, 0xfe225678, 0xfe22d95f, 0xfe234ffb, - 0xfe23ba4a, 0xfe241849, 0xfe2469f2, 0xfe24af3c, 0xfe24e81e, - 0xfe25148b, 0xfe253474, 0xfe2547c7, 0xfe254e70, 0xfe25485a, - 0xfe25356a, 0xfe251586, 0xfe24e88f, 0xfe24ae64, 0xfe2466e1, - 0xfe2411df, 0xfe23af34, 0xfe233eb4, 0xfe22c02c, 0xfe22336b, - 0xfe219838, 0xfe20ee58, 0xfe20358c, 0xfe1f6d92, 0xfe1e9621, - 0xfe1daef0, 0xfe1cb7ac, 0xfe1bb002, 0xfe1a9798, 0xfe196e0d, - 0xfe1832fd, 0xfe16e5fe, 0xfe15869d, 0xfe141464, 0xfe128ed3, - 0xfe10f565, 0xfe0f478c, 0xfe0d84b1, 0xfe0bac36, 0xfe09bd73, - 0xfe07b7b5, 0xfe059a40, 0xfe03644c, 0xfe011504, 0xfdfeab88, - 0xfdfc26e9, 0xfdf98629, 0xfdf6c83b, 0xfdf3ec01, 0xfdf0f04a, - 0xfdedd3d1, 0xfdea953d, 0xfde7331e, 0xfde3abe9, 0xfddffdfb, - 0xfddc2791, 0xfdd826cd, 0xfdd3f9a8, 0xfdcf9dfc, 0xfdcb1176, - 0xfdc65198, 0xfdc15bb3, 0xfdbc2ce2, 0xfdb6c206, 0xfdb117be, - 0xfdab2a63, 0xfda4f5fd, 0xfd9e7640, 0xfd97a67a, 0xfd908192, - 0xfd8901f2, 0xfd812182, 0xfd78d98e, 0xfd7022bb, 0xfd66f4ed, - 0xfd5d4732, 0xfd530f9c, 0xfd48432b, 0xfd3cd59a, 0xfd30b936, - 0xfd23dea4, 0xfd16349e, 0xfd07a7a3, 0xfcf8219b, 0xfce7895b, - 0xfcd5c220, 0xfcc2aadb, 0xfcae1d5e, 0xfc97ed4e, 0xfc7fe6d4, - 0xfc65ccf3, 0xfc495762, 0xfc2a2fc8, 0xfc07ee19, 0xfbe213c1, - 0xfbb8051a, 0xfb890078, 0xfb5411a5, 0xfb180005, 0xfad33482, - 0xfa839276, 0xfa263b32, 0xf9b72d1c, 0xf930a1a2, 0xf889f023, - 0xf7b577d2, 0xf69c650c, 0xf51530f0, 0xf2cb0e3c, 0xeeefb15d, - 0xe6da6ecf, -} -var we = [256]float32{ - 2.0249555e-09, 1.486674e-11, 2.4409617e-11, 3.1968806e-11, - 3.844677e-11, 4.4228204e-11, 4.9516443e-11, 5.443359e-11, - 5.905944e-11, 6.344942e-11, 6.7643814e-11, 7.1672945e-11, - 7.556032e-11, 7.932458e-11, 8.298079e-11, 8.654132e-11, - 9.0016515e-11, 9.3415074e-11, 9.674443e-11, 1.0001099e-10, - 1.03220314e-10, 1.06377254e-10, 1.09486115e-10, 1.1255068e-10, - 1.1557435e-10, 1.1856015e-10, 1.2151083e-10, 1.2442886e-10, - 1.2731648e-10, 1.3017575e-10, 1.3300853e-10, 1.3581657e-10, - 1.3860142e-10, 1.4136457e-10, 1.4410738e-10, 1.4683108e-10, - 1.4953687e-10, 1.5222583e-10, 1.54899e-10, 1.5755733e-10, - 1.6020171e-10, 1.6283301e-10, 1.6545203e-10, 1.6805951e-10, - 1.7065617e-10, 1.732427e-10, 1.7581973e-10, 1.7838787e-10, - 1.8094774e-10, 1.8349985e-10, 1.8604476e-10, 1.8858298e-10, - 1.9111498e-10, 1.9364126e-10, 1.9616223e-10, 1.9867835e-10, - 2.0119004e-10, 2.0369768e-10, 2.0620168e-10, 2.087024e-10, - 2.1120022e-10, 2.136955e-10, 2.1618855e-10, 2.1867974e-10, - 2.2116936e-10, 2.2365775e-10, 2.261452e-10, 2.2863202e-10, - 2.311185e-10, 2.3360494e-10, 2.360916e-10, 2.3857874e-10, - 2.4106667e-10, 2.4355562e-10, 2.4604588e-10, 2.485377e-10, - 2.5103128e-10, 2.5352695e-10, 2.560249e-10, 2.585254e-10, - 2.6102867e-10, 2.6353494e-10, 2.6604446e-10, 2.6855745e-10, - 2.7107416e-10, 2.7359479e-10, 2.761196e-10, 2.7864877e-10, - 2.8118255e-10, 2.8372119e-10, 2.8626485e-10, 2.888138e-10, - 2.9136826e-10, 2.939284e-10, 2.9649452e-10, 2.9906677e-10, - 3.016454e-10, 3.0423064e-10, 3.0682268e-10, 3.0942177e-10, - 3.1202813e-10, 3.1464195e-10, 3.1726352e-10, 3.19893e-10, - 3.2253064e-10, 3.251767e-10, 3.2783135e-10, 3.3049485e-10, - 3.3316744e-10, 3.3584938e-10, 3.3854083e-10, 3.4124212e-10, - 3.4395342e-10, 3.46675e-10, 3.4940711e-10, 3.5215003e-10, - 3.5490397e-10, 3.5766917e-10, 3.6044595e-10, 3.6323455e-10, - 3.660352e-10, 3.6884823e-10, 3.7167386e-10, 3.745124e-10, - 3.773641e-10, 3.802293e-10, 3.8310827e-10, 3.860013e-10, - 3.8890866e-10, 3.918307e-10, 3.9476775e-10, 3.9772008e-10, - 4.0068804e-10, 4.0367196e-10, 4.0667217e-10, 4.09689e-10, - 4.1272286e-10, 4.1577405e-10, 4.1884296e-10, 4.2192994e-10, - 4.250354e-10, 4.281597e-10, 4.313033e-10, 4.3446652e-10, - 4.3764986e-10, 4.408537e-10, 4.4407847e-10, 4.4732465e-10, - 4.5059267e-10, 4.5388301e-10, 4.571962e-10, 4.6053267e-10, - 4.6389292e-10, 4.6727755e-10, 4.70687e-10, 4.741219e-10, - 4.7758275e-10, 4.810702e-10, 4.845848e-10, 4.8812715e-10, - 4.9169796e-10, 4.9529775e-10, 4.989273e-10, 5.0258725e-10, - 5.0627835e-10, 5.100013e-10, 5.1375687e-10, 5.1754584e-10, - 5.21369e-10, 5.2522725e-10, 5.2912136e-10, 5.330522e-10, - 5.370208e-10, 5.4102806e-10, 5.45075e-10, 5.491625e-10, - 5.532918e-10, 5.5746385e-10, 5.616799e-10, 5.6594107e-10, - 5.7024857e-10, 5.746037e-10, 5.7900773e-10, 5.834621e-10, - 5.8796823e-10, 5.925276e-10, 5.971417e-10, 6.018122e-10, - 6.065408e-10, 6.113292e-10, 6.1617933e-10, 6.2109295e-10, - 6.260722e-10, 6.3111916e-10, 6.3623595e-10, 6.4142497e-10, - 6.4668854e-10, 6.5202926e-10, 6.5744976e-10, 6.6295286e-10, - 6.6854156e-10, 6.742188e-10, 6.79988e-10, 6.858526e-10, - 6.9181616e-10, 6.978826e-10, 7.04056e-10, 7.103407e-10, - 7.167412e-10, 7.2326256e-10, 7.2990985e-10, 7.366886e-10, - 7.4360473e-10, 7.5066453e-10, 7.5787476e-10, 7.6524265e-10, - 7.7277595e-10, 7.80483e-10, 7.883728e-10, 7.9645507e-10, - 8.047402e-10, 8.1323964e-10, 8.219657e-10, 8.309319e-10, - 8.401528e-10, 8.496445e-10, 8.594247e-10, 8.6951274e-10, - 8.799301e-10, 8.9070046e-10, 9.018503e-10, 9.134092e-10, - 9.254101e-10, 9.378904e-10, 9.508923e-10, 9.644638e-10, - 9.786603e-10, 9.935448e-10, 1.0091913e-09, 1.025686e-09, - 1.0431306e-09, 1.0616465e-09, 1.08138e-09, 1.1025096e-09, - 1.1252564e-09, 1.1498986e-09, 1.1767932e-09, 1.206409e-09, - 1.2393786e-09, 1.276585e-09, 1.3193139e-09, 1.3695435e-09, - 1.4305498e-09, 1.508365e-09, 1.6160854e-09, 1.7921248e-09, -} -var fe = [256]float32{ - 1, 0.9381437, 0.90046996, 0.87170434, 0.8477855, 0.8269933, - 0.8084217, 0.7915276, 0.77595687, 0.7614634, 0.7478686, - 0.7350381, 0.72286767, 0.71127474, 0.70019263, 0.6895665, - 0.67935055, 0.6695063, 0.66000086, 0.65080583, 0.6418967, - 0.63325197, 0.6248527, 0.6166822, 0.60872537, 0.60096896, - 0.5934009, 0.58601034, 0.5787874, 0.57172304, 0.5648092, - 0.5580383, 0.5514034, 0.5448982, 0.5385169, 0.53225386, - 0.5261042, 0.52006316, 0.5141264, 0.50828975, 0.5025495, - 0.496902, 0.49134386, 0.485872, 0.48048335, 0.4751752, - 0.46994483, 0.46478975, 0.45970762, 0.45469615, 0.44975325, - 0.44487688, 0.44006512, 0.43531612, 0.43062815, 0.42599955, - 0.42142874, 0.4169142, 0.41245446, 0.40804818, 0.403694, - 0.3993907, 0.39513698, 0.39093173, 0.38677382, 0.38266218, - 0.37859577, 0.37457356, 0.37059465, 0.3666581, 0.362763, - 0.35890847, 0.35509375, 0.351318, 0.3475805, 0.34388044, - 0.34021714, 0.3365899, 0.33299807, 0.32944095, 0.32591796, - 0.3224285, 0.3189719, 0.31554767, 0.31215525, 0.30879408, - 0.3054636, 0.3021634, 0.29889292, 0.2956517, 0.29243928, - 0.28925523, 0.28609908, 0.28297043, 0.27986884, 0.27679393, - 0.2737453, 0.2707226, 0.2677254, 0.26475343, 0.26180625, - 0.25888354, 0.25598502, 0.2531103, 0.25025907, 0.24743107, - 0.24462597, 0.24184346, 0.23908329, 0.23634516, 0.23362878, - 0.23093392, 0.2282603, 0.22560766, 0.22297576, 0.22036438, - 0.21777324, 0.21520215, 0.21265087, 0.21011916, 0.20760682, - 0.20511365, 0.20263945, 0.20018397, 0.19774707, 0.19532852, - 0.19292815, 0.19054577, 0.1881812, 0.18583426, 0.18350479, - 0.1811926, 0.17889754, 0.17661946, 0.17435817, 0.17211354, - 0.1698854, 0.16767362, 0.16547804, 0.16329853, 0.16113494, - 0.15898713, 0.15685499, 0.15473837, 0.15263714, 0.15055119, - 0.14848037, 0.14642459, 0.14438373, 0.14235765, 0.14034624, - 0.13834943, 0.13636707, 0.13439907, 0.13244532, 0.13050574, - 0.1285802, 0.12666863, 0.12477092, 0.12288698, 0.12101672, - 0.119160056, 0.1173169, 0.115487166, 0.11367077, 0.11186763, - 0.11007768, 0.10830083, 0.10653701, 0.10478614, 0.10304816, - 0.101323, 0.09961058, 0.09791085, 0.09622374, 0.09454919, - 0.09288713, 0.091237515, 0.08960028, 0.087975375, 0.08636274, - 0.08476233, 0.083174095, 0.081597984, 0.08003395, 0.07848195, - 0.076941945, 0.07541389, 0.07389775, 0.072393484, 0.07090106, - 0.069420435, 0.06795159, 0.066494495, 0.06504912, 0.063615434, - 0.062193416, 0.060783047, 0.059384305, 0.057997175, - 0.05662164, 0.05525769, 0.053905312, 0.052564494, 0.051235236, - 0.049917534, 0.048611384, 0.047316793, 0.046033762, 0.0447623, - 0.043502413, 0.042254124, 0.041017443, 0.039792392, - 0.038578995, 0.037377283, 0.036187284, 0.035009038, - 0.033842582, 0.032687962, 0.031545233, 0.030414443, 0.02929566, - 0.02818895, 0.027094385, 0.026012046, 0.024942026, 0.023884421, - 0.022839336, 0.021806888, 0.020787204, 0.019780423, 0.0187867, - 0.0178062, 0.016839107, 0.015885621, 0.014945968, 0.014020392, - 0.013109165, 0.012212592, 0.011331013, 0.01046481, 0.009614414, - 0.008780315, 0.007963077, 0.0071633533, 0.006381906, - 0.0056196423, 0.0048776558, 0.004157295, 0.0034602648, - 0.0027887989, 0.0021459677, 0.0015362998, 0.0009672693, - 0.00045413437, -} diff --git a/vendor/golang.org/x/exp/rand/normal.go b/vendor/golang.org/x/exp/rand/normal.go deleted file mode 100644 index b66da3a81a..0000000000 --- a/vendor/golang.org/x/exp/rand/normal.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rand - -import ( - "math" -) - -/* - * Normal distribution - * - * See "The Ziggurat Method for Generating Random Variables" - * (Marsaglia & Tsang, 2000) - * http://www.jstatsoft.org/v05/i08/paper [pdf] - */ - -const ( - rn = 3.442619855899 -) - -func absInt32(i int32) uint32 { - if i < 0 { - return uint32(-i) - } - return uint32(i) -} - -// NormFloat64 returns a normally distributed float64 in the range -// [-math.MaxFloat64, +math.MaxFloat64] with -// standard normal distribution (mean = 0, stddev = 1). -// To produce a different normal distribution, callers can -// adjust the output using: -// -// sample = NormFloat64() * desiredStdDev + desiredMean -func (r *Rand) NormFloat64() float64 { - for { - j := int32(r.Uint32()) // Possibly negative - i := j & 0x7F - x := float64(j) * float64(wn[i]) - if absInt32(j) < kn[i] { - // This case should be hit better than 99% of the time. - return x - } - - if i == 0 { - // This extra work is only required for the base strip. - for { - x = -math.Log(r.Float64()) * (1.0 / rn) - y := -math.Log(r.Float64()) - if y+y >= x*x { - break - } - } - if j > 0 { - return rn + x - } - return -rn - x - } - if fn[i]+float32(r.Float64())*(fn[i-1]-fn[i]) < float32(math.Exp(-.5*x*x)) { - return x - } - } -} - -var kn = [128]uint32{ - 0x76ad2212, 0x0, 0x600f1b53, 0x6ce447a6, 0x725b46a2, - 0x7560051d, 0x774921eb, 0x789a25bd, 0x799045c3, 0x7a4bce5d, - 0x7adf629f, 0x7b5682a6, 0x7bb8a8c6, 0x7c0ae722, 0x7c50cce7, - 0x7c8cec5b, 0x7cc12cd6, 0x7ceefed2, 0x7d177e0b, 0x7d3b8883, - 0x7d5bce6c, 0x7d78dd64, 0x7d932886, 0x7dab0e57, 0x7dc0dd30, - 0x7dd4d688, 0x7de73185, 0x7df81cea, 0x7e07c0a3, 0x7e163efa, - 0x7e23b587, 0x7e303dfd, 0x7e3beec2, 0x7e46db77, 0x7e51155d, - 0x7e5aabb3, 0x7e63abf7, 0x7e6c222c, 0x7e741906, 0x7e7b9a18, - 0x7e82adfa, 0x7e895c63, 0x7e8fac4b, 0x7e95a3fb, 0x7e9b4924, - 0x7ea0a0ef, 0x7ea5b00d, 0x7eaa7ac3, 0x7eaf04f3, 0x7eb3522a, - 0x7eb765a5, 0x7ebb4259, 0x7ebeeafd, 0x7ec2620a, 0x7ec5a9c4, - 0x7ec8c441, 0x7ecbb365, 0x7ece78ed, 0x7ed11671, 0x7ed38d62, - 0x7ed5df12, 0x7ed80cb4, 0x7eda175c, 0x7edc0005, 0x7eddc78e, - 0x7edf6ebf, 0x7ee0f647, 0x7ee25ebe, 0x7ee3a8a9, 0x7ee4d473, - 0x7ee5e276, 0x7ee6d2f5, 0x7ee7a620, 0x7ee85c10, 0x7ee8f4cd, - 0x7ee97047, 0x7ee9ce59, 0x7eea0eca, 0x7eea3147, 0x7eea3568, - 0x7eea1aab, 0x7ee9e071, 0x7ee98602, 0x7ee90a88, 0x7ee86d08, - 0x7ee7ac6a, 0x7ee6c769, 0x7ee5bc9c, 0x7ee48a67, 0x7ee32efc, - 0x7ee1a857, 0x7edff42f, 0x7ede0ffa, 0x7edbf8d9, 0x7ed9ab94, - 0x7ed7248d, 0x7ed45fae, 0x7ed1585c, 0x7ece095f, 0x7eca6ccb, - 0x7ec67be2, 0x7ec22eee, 0x7ebd7d1a, 0x7eb85c35, 0x7eb2c075, - 0x7eac9c20, 0x7ea5df27, 0x7e9e769f, 0x7e964c16, 0x7e8d44ba, - 0x7e834033, 0x7e781728, 0x7e6b9933, 0x7e5d8a1a, 0x7e4d9ded, - 0x7e3b737a, 0x7e268c2f, 0x7e0e3ff5, 0x7df1aa5d, 0x7dcf8c72, - 0x7da61a1e, 0x7d72a0fb, 0x7d30e097, 0x7cd9b4ab, 0x7c600f1a, - 0x7ba90bdc, 0x7a722176, 0x77d664e5, -} -var wn = [128]float32{ - 1.7290405e-09, 1.2680929e-10, 1.6897518e-10, 1.9862688e-10, - 2.2232431e-10, 2.4244937e-10, 2.601613e-10, 2.7611988e-10, - 2.9073963e-10, 3.042997e-10, 3.1699796e-10, 3.289802e-10, - 3.4035738e-10, 3.5121603e-10, 3.616251e-10, 3.7164058e-10, - 3.8130857e-10, 3.9066758e-10, 3.9975012e-10, 4.08584e-10, - 4.1719309e-10, 4.2559822e-10, 4.338176e-10, 4.418672e-10, - 4.497613e-10, 4.5751258e-10, 4.651324e-10, 4.7263105e-10, - 4.8001775e-10, 4.87301e-10, 4.944885e-10, 5.015873e-10, - 5.0860405e-10, 5.155446e-10, 5.2241467e-10, 5.2921934e-10, - 5.359635e-10, 5.426517e-10, 5.4928817e-10, 5.5587696e-10, - 5.624219e-10, 5.6892646e-10, 5.753941e-10, 5.818282e-10, - 5.882317e-10, 5.946077e-10, 6.00959e-10, 6.072884e-10, - 6.135985e-10, 6.19892e-10, 6.2617134e-10, 6.3243905e-10, - 6.386974e-10, 6.449488e-10, 6.511956e-10, 6.5744005e-10, - 6.6368433e-10, 6.699307e-10, 6.7618144e-10, 6.824387e-10, - 6.8870465e-10, 6.949815e-10, 7.012715e-10, 7.075768e-10, - 7.1389966e-10, 7.202424e-10, 7.266073e-10, 7.329966e-10, - 7.394128e-10, 7.4585826e-10, 7.5233547e-10, 7.58847e-10, - 7.653954e-10, 7.719835e-10, 7.7861395e-10, 7.852897e-10, - 7.920138e-10, 7.987892e-10, 8.0561924e-10, 8.125073e-10, - 8.194569e-10, 8.2647167e-10, 8.3355556e-10, 8.407127e-10, - 8.479473e-10, 8.55264e-10, 8.6266755e-10, 8.7016316e-10, - 8.777562e-10, 8.8545243e-10, 8.932582e-10, 9.0117996e-10, - 9.09225e-10, 9.174008e-10, 9.2571584e-10, 9.341788e-10, - 9.427997e-10, 9.515889e-10, 9.605579e-10, 9.697193e-10, - 9.790869e-10, 9.88676e-10, 9.985036e-10, 1.0085882e-09, - 1.0189509e-09, 1.0296151e-09, 1.0406069e-09, 1.0519566e-09, - 1.063698e-09, 1.0758702e-09, 1.0885183e-09, 1.1016947e-09, - 1.1154611e-09, 1.1298902e-09, 1.1450696e-09, 1.1611052e-09, - 1.1781276e-09, 1.1962995e-09, 1.2158287e-09, 1.2369856e-09, - 1.2601323e-09, 1.2857697e-09, 1.3146202e-09, 1.347784e-09, - 1.3870636e-09, 1.4357403e-09, 1.5008659e-09, 1.6030948e-09, -} -var fn = [128]float32{ - 1, 0.9635997, 0.9362827, 0.9130436, 0.89228165, 0.87324303, - 0.8555006, 0.8387836, 0.8229072, 0.8077383, 0.793177, - 0.7791461, 0.7655842, 0.7524416, 0.73967725, 0.7272569, - 0.7151515, 0.7033361, 0.69178915, 0.68049186, 0.6694277, - 0.658582, 0.6479418, 0.63749546, 0.6272325, 0.6171434, - 0.6072195, 0.5974532, 0.58783704, 0.5783647, 0.56903, - 0.5598274, 0.5507518, 0.54179835, 0.5329627, 0.52424055, - 0.5156282, 0.50712204, 0.49871865, 0.49041483, 0.48220766, - 0.4740943, 0.46607214, 0.4581387, 0.45029163, 0.44252872, - 0.43484783, 0.427247, 0.41972435, 0.41227803, 0.40490642, - 0.39760786, 0.3903808, 0.3832238, 0.37613547, 0.36911446, - 0.3621595, 0.35526937, 0.34844297, 0.34167916, 0.33497685, - 0.3283351, 0.3217529, 0.3152294, 0.30876362, 0.30235484, - 0.29600215, 0.28970486, 0.2834622, 0.2772735, 0.27113807, - 0.2650553, 0.25902456, 0.2530453, 0.24711695, 0.241239, - 0.23541094, 0.22963232, 0.2239027, 0.21822165, 0.21258877, - 0.20700371, 0.20146611, 0.19597565, 0.19053204, 0.18513499, - 0.17978427, 0.17447963, 0.1692209, 0.16400786, 0.15884037, - 0.15371831, 0.14864157, 0.14361008, 0.13862377, 0.13368265, - 0.12878671, 0.12393598, 0.119130544, 0.11437051, 0.10965602, - 0.104987256, 0.10036444, 0.095787846, 0.0912578, 0.08677467, - 0.0823389, 0.077950984, 0.073611505, 0.06932112, 0.06508058, - 0.06089077, 0.056752663, 0.0526674, 0.048636295, 0.044660863, - 0.040742867, 0.03688439, 0.033087887, 0.029356318, - 0.025693292, 0.022103304, 0.018592102, 0.015167298, - 0.011839478, 0.008624485, 0.005548995, 0.0026696292, -} diff --git a/vendor/golang.org/x/exp/rand/rand.go b/vendor/golang.org/x/exp/rand/rand.go deleted file mode 100644 index ee6161bc61..0000000000 --- a/vendor/golang.org/x/exp/rand/rand.go +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package rand implements pseudo-random number generators. -// -// Random numbers are generated by a Source. Top-level functions, such as -// Float64 and Int, use a default shared Source that produces a deterministic -// sequence of values each time a program is run. Use the Seed function to -// initialize the default Source if different behavior is required for each run. -// The default Source, a LockedSource, is safe for concurrent use by multiple -// goroutines, but Sources created by NewSource are not. However, Sources are small -// and it is reasonable to have a separate Source for each goroutine, seeded -// differently, to avoid locking. -// -// For random numbers suitable for security-sensitive work, see the crypto/rand -// package. -package rand - -import "sync" - -// A Source represents a source of uniformly-distributed -// pseudo-random int64 values in the range [0, 1<<64). -type Source interface { - Uint64() uint64 - Seed(seed uint64) -} - -// NewSource returns a new pseudo-random Source seeded with the given value. -func NewSource(seed uint64) Source { - var rng PCGSource - rng.Seed(seed) - return &rng -} - -// A Rand is a source of random numbers. -type Rand struct { - src Source - - // readVal contains remainder of 64-bit integer used for bytes - // generation during most recent Read call. - // It is saved so next Read call can start where the previous - // one finished. - readVal uint64 - // readPos indicates the number of low-order bytes of readVal - // that are still valid. - readPos int8 -} - -// New returns a new Rand that uses random values from src -// to generate other random values. -func New(src Source) *Rand { - return &Rand{src: src} -} - -// Seed uses the provided seed value to initialize the generator to a deterministic state. -// Seed should not be called concurrently with any other Rand method. -func (r *Rand) Seed(seed uint64) { - if lk, ok := r.src.(*LockedSource); ok { - lk.seedPos(seed, &r.readPos) - return - } - - r.src.Seed(seed) - r.readPos = 0 -} - -// Uint64 returns a pseudo-random 64-bit integer as a uint64. -func (r *Rand) Uint64() uint64 { return r.src.Uint64() } - -// Int63 returns a non-negative pseudo-random 63-bit integer as an int64. -func (r *Rand) Int63() int64 { return int64(r.src.Uint64() &^ (1 << 63)) } - -// Uint32 returns a pseudo-random 32-bit value as a uint32. -func (r *Rand) Uint32() uint32 { return uint32(r.Uint64() >> 32) } - -// Int31 returns a non-negative pseudo-random 31-bit integer as an int32. -func (r *Rand) Int31() int32 { return int32(r.Uint64() >> 33) } - -// Int returns a non-negative pseudo-random int. -func (r *Rand) Int() int { - u := uint(r.Uint64()) - return int(u << 1 >> 1) // clear sign bit. -} - -const maxUint64 = (1 << 64) - 1 - -// Uint64n returns, as a uint64, a pseudo-random number in [0,n). -// It is guaranteed more uniform than taking a Source value mod n -// for any n that is not a power of 2. -func (r *Rand) Uint64n(n uint64) uint64 { - if n&(n-1) == 0 { // n is power of two, can mask - if n == 0 { - panic("invalid argument to Uint64n") - } - return r.Uint64() & (n - 1) - } - // If n does not divide v, to avoid bias we must not use - // a v that is within maxUint64%n of the top of the range. - v := r.Uint64() - if v > maxUint64-n { // Fast check. - ceiling := maxUint64 - maxUint64%n - for v >= ceiling { - v = r.Uint64() - } - } - - return v % n -} - -// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n). -// It panics if n <= 0. -func (r *Rand) Int63n(n int64) int64 { - if n <= 0 { - panic("invalid argument to Int63n") - } - return int64(r.Uint64n(uint64(n))) -} - -// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n). -// It panics if n <= 0. -func (r *Rand) Int31n(n int32) int32 { - if n <= 0 { - panic("invalid argument to Int31n") - } - // TODO: Avoid some 64-bit ops to make it more efficient on 32-bit machines. - return int32(r.Uint64n(uint64(n))) -} - -// Intn returns, as an int, a non-negative pseudo-random number in [0,n). -// It panics if n <= 0. -func (r *Rand) Intn(n int) int { - if n <= 0 { - panic("invalid argument to Intn") - } - // TODO: Avoid some 64-bit ops to make it more efficient on 32-bit machines. - return int(r.Uint64n(uint64(n))) -} - -// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0). -func (r *Rand) Float64() float64 { - // There is one bug in the value stream: r.Int63() may be so close - // to 1<<63 that the division rounds up to 1.0, and we've guaranteed - // that the result is always less than 1.0. - // - // We tried to fix this by mapping 1.0 back to 0.0, but since float64 - // values near 0 are much denser than near 1, mapping 1 to 0 caused - // a theoretically significant overshoot in the probability of returning 0. - // Instead of that, if we round up to 1, just try again. - // Getting 1 only happens 1/2⁵³ of the time, so most clients - // will not observe it anyway. -again: - f := float64(r.Uint64n(1<<53)) / (1 << 53) - if f == 1.0 { - goto again // resample; this branch is taken O(never) - } - return f -} - -// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0). -func (r *Rand) Float32() float32 { - // We do not want to return 1.0. - // This only happens 1/2²⁴ of the time (plus the 1/2⁵³ of the time in Float64). -again: - f := float32(r.Float64()) - if f == 1 { - goto again // resample; this branch is taken O(very rarely) - } - return f -} - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n). -func (r *Rand) Perm(n int) []int { - m := make([]int, n) - // In the following loop, the iteration when i=0 always swaps m[0] with m[0]. - // A change to remove this useless iteration is to assign 1 to i in the init - // statement. But Perm also effects r. Making this change will affect - // the final state of r. So this change can't be made for compatibility - // reasons for Go 1. - for i := 0; i < n; i++ { - j := r.Intn(i + 1) - m[i] = m[j] - m[j] = i - } - return m -} - -// Shuffle pseudo-randomizes the order of elements. -// n is the number of elements. Shuffle panics if n < 0. -// swap swaps the elements with indexes i and j. -func (r *Rand) Shuffle(n int, swap func(i, j int)) { - if n < 0 { - panic("invalid argument to Shuffle") - } - - // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle - // Shuffle really ought not be called with n that doesn't fit in 32 bits. - // Not only will it take a very long time, but with 2³¹! possible permutations, - // there's no way that any PRNG can have a big enough internal state to - // generate even a minuscule percentage of the possible permutations. - // Nevertheless, the right API signature accepts an int n, so handle it as best we can. - i := n - 1 - for ; i > 1<<31-1-1; i-- { - j := int(r.Int63n(int64(i + 1))) - swap(i, j) - } - for ; i > 0; i-- { - j := int(r.Int31n(int32(i + 1))) - swap(i, j) - } -} - -// Read generates len(p) random bytes and writes them into p. It -// always returns len(p) and a nil error. -// Read should not be called concurrently with any other Rand method unless -// the underlying source is a LockedSource. -func (r *Rand) Read(p []byte) (n int, err error) { - if lk, ok := r.src.(*LockedSource); ok { - return lk.Read(p, &r.readVal, &r.readPos) - } - return read(p, r.src, &r.readVal, &r.readPos) -} - -func read(p []byte, src Source, readVal *uint64, readPos *int8) (n int, err error) { - pos := *readPos - val := *readVal - rng, _ := src.(*PCGSource) - for n = 0; n < len(p); n++ { - if pos == 0 { - if rng != nil { - val = rng.Uint64() - } else { - val = src.Uint64() - } - pos = 8 - } - p[n] = byte(val) - val >>= 8 - pos-- - } - *readPos = pos - *readVal = val - return -} - -/* - * Top-level convenience functions - */ - -var globalRand = New(&LockedSource{src: *NewSource(1).(*PCGSource)}) - -// Type assert that globalRand's source is a LockedSource whose src is a PCGSource. -var _ PCGSource = globalRand.src.(*LockedSource).src - -// Seed uses the provided seed value to initialize the default Source to a -// deterministic state. If Seed is not called, the generator behaves as -// if seeded by Seed(1). -// Seed, unlike the Rand.Seed method, is safe for concurrent use. -func Seed(seed uint64) { globalRand.Seed(seed) } - -// Int63 returns a non-negative pseudo-random 63-bit integer as an int64 -// from the default Source. -func Int63() int64 { return globalRand.Int63() } - -// Uint32 returns a pseudo-random 32-bit value as a uint32 -// from the default Source. -func Uint32() uint32 { return globalRand.Uint32() } - -// Uint64 returns a pseudo-random 64-bit value as a uint64 -// from the default Source. -func Uint64() uint64 { return globalRand.Uint64() } - -// Int31 returns a non-negative pseudo-random 31-bit integer as an int32 -// from the default Source. -func Int31() int32 { return globalRand.Int31() } - -// Int returns a non-negative pseudo-random int from the default Source. -func Int() int { return globalRand.Int() } - -// Int63n returns, as an int64, a non-negative pseudo-random number in [0,n) -// from the default Source. -// It panics if n <= 0. -func Int63n(n int64) int64 { return globalRand.Int63n(n) } - -// Int31n returns, as an int32, a non-negative pseudo-random number in [0,n) -// from the default Source. -// It panics if n <= 0. -func Int31n(n int32) int32 { return globalRand.Int31n(n) } - -// Intn returns, as an int, a non-negative pseudo-random number in [0,n) -// from the default Source. -// It panics if n <= 0. -func Intn(n int) int { return globalRand.Intn(n) } - -// Float64 returns, as a float64, a pseudo-random number in [0.0,1.0) -// from the default Source. -func Float64() float64 { return globalRand.Float64() } - -// Float32 returns, as a float32, a pseudo-random number in [0.0,1.0) -// from the default Source. -func Float32() float32 { return globalRand.Float32() } - -// Perm returns, as a slice of n ints, a pseudo-random permutation of the integers [0,n) -// from the default Source. -func Perm(n int) []int { return globalRand.Perm(n) } - -// Shuffle pseudo-randomizes the order of elements using the default Source. -// n is the number of elements. Shuffle panics if n < 0. -// swap swaps the elements with indexes i and j. -func Shuffle(n int, swap func(i, j int)) { globalRand.Shuffle(n, swap) } - -// Read generates len(p) random bytes from the default Source and -// writes them into p. It always returns len(p) and a nil error. -// Read, unlike the Rand.Read method, is safe for concurrent use. -func Read(p []byte) (n int, err error) { return globalRand.Read(p) } - -// NormFloat64 returns a normally distributed float64 in the range -// [-math.MaxFloat64, +math.MaxFloat64] with -// standard normal distribution (mean = 0, stddev = 1) -// from the default Source. -// To produce a different normal distribution, callers can -// adjust the output using: -// -// sample = NormFloat64() * desiredStdDev + desiredMean -func NormFloat64() float64 { return globalRand.NormFloat64() } - -// ExpFloat64 returns an exponentially distributed float64 in the range -// (0, +math.MaxFloat64] with an exponential distribution whose rate parameter -// (lambda) is 1 and whose mean is 1/lambda (1) from the default Source. -// To produce a distribution with a different rate parameter, -// callers can adjust the output using: -// -// sample = ExpFloat64() / desiredRateParameter -func ExpFloat64() float64 { return globalRand.ExpFloat64() } - -// LockedSource is an implementation of Source that is concurrency-safe. -// A Rand using a LockedSource is safe for concurrent use. -// -// The zero value of LockedSource is valid, but should be seeded before use. -type LockedSource struct { - lk sync.Mutex - src PCGSource -} - -func (s *LockedSource) Uint64() (n uint64) { - s.lk.Lock() - n = s.src.Uint64() - s.lk.Unlock() - return -} - -func (s *LockedSource) Seed(seed uint64) { - s.lk.Lock() - s.src.Seed(seed) - s.lk.Unlock() -} - -// seedPos implements Seed for a LockedSource without a race condiiton. -func (s *LockedSource) seedPos(seed uint64, readPos *int8) { - s.lk.Lock() - s.src.Seed(seed) - *readPos = 0 - s.lk.Unlock() -} - -// Read implements Read for a LockedSource. -func (s *LockedSource) Read(p []byte, readVal *uint64, readPos *int8) (n int, err error) { - s.lk.Lock() - n, err = read(p, &s.src, readVal, readPos) - s.lk.Unlock() - return -} diff --git a/vendor/golang.org/x/exp/rand/rng.go b/vendor/golang.org/x/exp/rand/rng.go deleted file mode 100644 index 9b79108c73..0000000000 --- a/vendor/golang.org/x/exp/rand/rng.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package rand - -import ( - "encoding/binary" - "io" - "math/bits" -) - -// PCGSource is an implementation of a 64-bit permuted congruential -// generator as defined in -// -// PCG: A Family of Simple Fast Space-Efficient Statistically Good -// Algorithms for Random Number Generation -// Melissa E. O’Neill, Harvey Mudd College -// http://www.pcg-random.org/pdf/toms-oneill-pcg-family-v1.02.pdf -// -// The generator here is the congruential generator PCG XSL RR 128/64 (LCG) -// as found in the software available at http://www.pcg-random.org/. -// It has period 2^128 with 128 bits of state, producing 64-bit values. -// Is state is represented by two uint64 words. -type PCGSource struct { - low uint64 - high uint64 -} - -const ( - maxUint32 = (1 << 32) - 1 - - multiplier = 47026247687942121848144207491837523525 - mulHigh = multiplier >> 64 - mulLow = multiplier & maxUint64 - - increment = 117397592171526113268558934119004209487 - incHigh = increment >> 64 - incLow = increment & maxUint64 - - // TODO: Use these? - initializer = 245720598905631564143578724636268694099 - initHigh = initializer >> 64 - initLow = initializer & maxUint64 -) - -// Seed uses the provided seed value to initialize the generator to a deterministic state. -func (pcg *PCGSource) Seed(seed uint64) { - pcg.low = seed - pcg.high = seed // TODO: What is right? -} - -// Uint64 returns a pseudo-random 64-bit unsigned integer as a uint64. -func (pcg *PCGSource) Uint64() uint64 { - pcg.multiply() - pcg.add() - // XOR high and low 64 bits together and rotate right by high 6 bits of state. - return bits.RotateLeft64(pcg.high^pcg.low, -int(pcg.high>>58)) -} - -func (pcg *PCGSource) add() { - var carry uint64 - pcg.low, carry = bits.Add64(pcg.low, incLow, 0) - pcg.high, _ = bits.Add64(pcg.high, incHigh, carry) -} - -func (pcg *PCGSource) multiply() { - hi, lo := bits.Mul64(pcg.low, mulLow) - hi += pcg.high * mulLow - hi += pcg.low * mulHigh - pcg.low = lo - pcg.high = hi -} - -// MarshalBinary returns the binary representation of the current state of the generator. -func (pcg *PCGSource) MarshalBinary() ([]byte, error) { - var buf [16]byte - binary.BigEndian.PutUint64(buf[:8], pcg.high) - binary.BigEndian.PutUint64(buf[8:], pcg.low) - return buf[:], nil -} - -// UnmarshalBinary sets the state of the generator to the state represented in data. -func (pcg *PCGSource) UnmarshalBinary(data []byte) error { - if len(data) < 16 { - return io.ErrUnexpectedEOF - } - pcg.low = binary.BigEndian.Uint64(data[8:]) - pcg.high = binary.BigEndian.Uint64(data[:8]) - return nil -} diff --git a/vendor/golang.org/x/exp/rand/zipf.go b/vendor/golang.org/x/exp/rand/zipf.go deleted file mode 100644 index f04c814eb7..0000000000 --- a/vendor/golang.org/x/exp/rand/zipf.go +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// W.Hormann, G.Derflinger: -// "Rejection-Inversion to Generate Variates -// from Monotone Discrete Distributions" -// http://eeyore.wu-wien.ac.at/papers/96-04-04.wh-der.ps.gz - -package rand - -import "math" - -// A Zipf generates Zipf distributed variates. -type Zipf struct { - r *Rand - imax float64 - v float64 - q float64 - s float64 - oneminusQ float64 - oneminusQinv float64 - hxm float64 - hx0minusHxm float64 -} - -func (z *Zipf) h(x float64) float64 { - return math.Exp(z.oneminusQ*math.Log(z.v+x)) * z.oneminusQinv -} - -func (z *Zipf) hinv(x float64) float64 { - return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v -} - -// NewZipf returns a Zipf variate generator. -// The generator generates values k ∈ [0, imax] -// such that P(k) is proportional to (v + k) ** (-s). -// Requirements: s > 1 and v >= 1. -func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf { - z := new(Zipf) - if s <= 1.0 || v < 1 { - return nil - } - z.r = r - z.imax = float64(imax) - z.v = v - z.q = s - z.oneminusQ = 1.0 - z.q - z.oneminusQinv = 1.0 / z.oneminusQ - z.hxm = z.h(z.imax + 0.5) - z.hx0minusHxm = z.h(0.5) - math.Exp(math.Log(z.v)*(-z.q)) - z.hxm - z.s = 1 - z.hinv(z.h(1.5)-math.Exp(-z.q*math.Log(z.v+1.0))) - return z -} - -// Uint64 returns a value drawn from the Zipf distribution described -// by the Zipf object. -func (z *Zipf) Uint64() uint64 { - if z == nil { - panic("rand: nil Zipf") - } - k := 0.0 - - for { - r := z.r.Float64() // r on [0,1] - ur := z.hxm + r*z.hx0minusHxm - x := z.hinv(ur) - k = math.Floor(x + 0.5) - if k-x <= z.s { - break - } - if ur >= z.h(k+0.5)-math.Exp(-math.Log(k+z.v)*z.q) { - break - } - } - return uint64(k) -} diff --git a/vendor/modules.txt b/vendor/modules.txt index a90cc2d1bd..b0ffa1d10a 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -107,7 +107,7 @@ github.com/powerman/deepequal # github.com/quic-go/qpack v0.5.1 ## explicit; go 1.22 github.com/quic-go/qpack -# github.com/quic-go/quic-go v0.50.1 +# github.com/quic-go/quic-go v0.51.0 ## explicit; go 1.23 github.com/quic-go/quic-go github.com/quic-go/quic-go/http3 @@ -145,9 +145,6 @@ golang.org/x/crypto/nacl/box golang.org/x/crypto/nacl/secretbox golang.org/x/crypto/poly1305 golang.org/x/crypto/salsa20/salsa -# golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 -## explicit; go 1.20 -golang.org/x/exp/rand # golang.org/x/mod v0.23.0 ## explicit; go 1.22.0 golang.org/x/mod/internal/lazyregexp