diff --git a/go.mod b/go.mod index 8146f7560f..2f74baa2ef 100644 --- a/go.mod +++ b/go.mod @@ -34,7 +34,7 @@ require ( github.com/prometheus/client_golang v1.23.0 github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.66.1 - github.com/quic-go/quic-go v0.55.0 + github.com/quic-go/quic-go v0.59.1 go.etcd.io/etcd/api/v3 v3.6.5 go.etcd.io/etcd/client/v3 v3.6.5 go.uber.org/automaxprocs v1.6.0 diff --git a/go.sum b/go.sum index ddbb4dc8b4..e6d93d5bc4 100644 --- a/go.sum +++ b/go.sum @@ -321,8 +321,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg= github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= -github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk= -github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U= +github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic= +github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3 h1:4+LEVOB87y175cLJC/mbsgKmoDOjrBldtXvioEy96WY= github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3/go.mod h1:vl5+MqJ1nBINuSsUI2mGgH79UweUT/B5Fy8857PqyyI= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= diff --git a/vendor/github.com/quic-go/quic-go/.golangci.yml b/vendor/github.com/quic-go/quic-go/.golangci.yml index 4a97047baf..cd2a3f87f5 100644 --- a/vendor/github.com/quic-go/quic-go/.golangci.yml +++ b/vendor/github.com/quic-go/quic-go/.golangci.yml @@ -53,6 +53,8 @@ linters: deny: - pkg: 'github.com/quic-go/quic-go/internal' desc: 'no dependency on quic-go/internal' + allow: + - 'github.com/quic-go/quic-go/internal/synctest' misspell: ignore-rules: - ect diff --git a/vendor/github.com/quic-go/quic-go/README.md b/vendor/github.com/quic-go/quic-go/README.md index 246c330490..85751dbe70 100644 --- a/vendor/github.com/quic-go/quic-go/README.md +++ b/vendor/github.com/quic-go/quic-go/README.md @@ -1,11 +1,14 @@ +
+
[](https://quic-go.net/docs/)
[](https://pkg.go.dev/github.com/quic-go/quic-go)
[](https://codecov.io/gh/quic-go/quic-go/)
-[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:quic-go)
+[](https://issues.oss-fuzz.com/issues?q=quic-go)
quic-go is an implementation of the QUIC protocol ([RFC 9000](https://datatracker.ietf.org/doc/html/rfc9000), [RFC 9001](https://datatracker.ietf.org/doc/html/rfc9001), [RFC 9002](https://datatracker.ietf.org/doc/html/rfc9002)) in Go. It has support for HTTP/3 ([RFC 9114](https://datatracker.ietf.org/doc/html/rfc9114)), including QPACK ([RFC 9204](https://datatracker.ietf.org/doc/html/rfc9204)) and HTTP Datagrams ([RFC 9297](https://datatracker.ietf.org/doc/html/rfc9297)).
@@ -34,6 +37,7 @@ Detailed documentation can be found on [quic-go.net](https://quic-go.net/docs/).
| [gost](https://github.com/go-gost/gost) | A simple security tunnel written in Go |  |
| [Hysteria](https://github.com/apernet/hysteria) | A powerful, lightning fast and censorship resistant proxy |  |
| [Mercure](https://github.com/dunglas/mercure) | An open, easy, fast, reliable and battery-efficient solution for real-time communications |  |
+| [nodepass](https://github.com/yosebyte/nodepass) | A secure, efficient TCP/UDP tunneling solution that delivers fast, reliable access across network restrictions using pre-established TCP/QUIC connections |  |
| [OONI Probe](https://github.com/ooni/probe-cli) | Next generation OONI Probe. Library and CLI tool. |  |
| [reverst](https://github.com/flipt-io/reverst) | Reverse Tunnels in Go over HTTP/3 and QUIC |  |
| [RoadRunner](https://github.com/roadrunner-server/roadrunner) | High-performance PHP application server, process manager written in Go and powered with plugins |  |
@@ -51,3 +55,7 @@ quic-go always aims to support the latest two Go releases.
## Contributing
We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with [help wanted](https://github.com/quic-go/quic-go/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22). If you have any questions, please feel free to reach out by opening an issue or leaving a comment.
+
+## License
+
+The code is licensed under the MIT license. The logo and brand assets are excluded from the MIT license. See [assets/LICENSE.md](https://github.com/quic-go/quic-go/tree/master/assets/LICENSE.md) for the full usage policy and details.
diff --git a/vendor/github.com/quic-go/quic-go/SECURITY.md b/vendor/github.com/quic-go/quic-go/SECURITY.md
index c24c08f863..79fe1f568f 100644
--- a/vendor/github.com/quic-go/quic-go/SECURITY.md
+++ b/vendor/github.com/quic-go/quic-go/SECURITY.md
@@ -1,19 +1,14 @@
# Security Policy
-quic-go still in development. This means that there may be problems in our protocols,
-or there may be mistakes in our implementations.
-We take security vulnerabilities very seriously. If you discover a security issue,
-please bring it to our attention right away!
+quic-go is an implementation of the QUIC protocol and related standards. No software is perfect, and we take reports of potential security issues very seriously.
## Reporting a Vulnerability
-If you find a vulnerability that may affect live deployments -- for example, by exposing
-a remote execution exploit -- please [**report privately**](https://github.com/quic-go/quic-go/security/advisories/new).
-Please **DO NOT file a public issue**.
+If you discover a vulnerability that could affect production deployments (e.g., a remotely exploitable issue), please report it [**privately**](https://github.com/quic-go/quic-go/security/advisories/new).
+Please **DO NOT file a public issue** for exploitable vulnerabilities.
-If the issue is an implementation weakness that cannot be immediately exploited or
-something not yet deployed, just discuss it openly.
+If the issue is theoretical, non-exploitable, or related to an experimental feature, you may discuss it openly by filing a regular issue.
-## Reporting a non security bug
+## Reporting a non-security bug
-For non-security bugs, please simply file a GitHub [issue](https://github.com/quic-go/quic-go/issues/new).
+For bugs, feature requests, or other non-security concerns, please open a GitHub [issue](https://github.com/quic-go/quic-go/issues/new).
diff --git a/vendor/github.com/quic-go/quic-go/codecov.yml b/vendor/github.com/quic-go/quic-go/codecov.yml
index e5a166ef3e..58c94e9bdd 100644
--- a/vendor/github.com/quic-go/quic-go/codecov.yml
+++ b/vendor/github.com/quic-go/quic-go/codecov.yml
@@ -9,8 +9,6 @@ coverage:
- internal/utils/linkedlist/linkedlist.go
- internal/testdata
- internal/synctest
- - logging/connection_tracer_multiplexer.go
- - logging/tracer_multiplexer.go
- testutils/
- fuzzing/
- metrics/
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 c2b3545052..133932a6a5 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
@@ -157,13 +157,6 @@ func (m *connIDGenerator) SetHandshakeComplete(connIDExpiry monotime.Time) {
}
}
-func (m *connIDGenerator) NextRetireTime() monotime.Time {
- if len(m.connIDsToRetire) == 0 {
- return 0
- }
- return m.connIDsToRetire[0].t
-}
-
func (m *connIDGenerator) RemoveRetiredConnIDs(now monotime.Time) {
if len(m.connIDsToRetire) == 0 {
return
diff --git a/vendor/github.com/quic-go/quic-go/connection.go b/vendor/github.com/quic-go/quic-go/connection.go
index 568086a111..1cb396fcc2 100644
--- a/vendor/github.com/quic-go/quic-go/connection.go
+++ b/vendor/github.com/quic-go/quic-go/connection.go
@@ -23,7 +23,8 @@ import (
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/internal/utils/ringbuffer"
"github.com/quic-go/quic-go/internal/wire"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
)
type unpacker interface {
@@ -56,6 +57,11 @@ type receivedPacket struct {
info packetInfo // only valid if the contained IP address is valid
}
+type receivedPacketWithDatagramID struct {
+ receivedPacket
+ datagramID qlog.DatagramID
+}
+
func (p *receivedPacket) Size() protocol.ByteCount { return protocol.ByteCount(len(p.data)) }
func (p *receivedPacket) Clone() *receivedPacket {
@@ -93,9 +99,6 @@ func (e *errCloseForRecreating) Error() string {
var deadlineSendImmediately = monotime.Time(42 * time.Millisecond) // any value > time.Time{} and before time.Now() is fine
-var connTracingID atomic.Uint64 // to be accessed atomically
-func nextConnTracingID() ConnectionTracingID { return ConnectionTracingID(connTracingID.Add(1)) }
-
type blockMode uint8
const (
@@ -182,8 +185,8 @@ type Conn struct {
ctxCancel context.CancelCauseFunc
handshakeCompleteChan chan struct{}
- undecryptablePackets []receivedPacket // undecryptable packets, waiting for a change in encryption level
- undecryptablePacketsToProcess []receivedPacket
+ undecryptablePackets []receivedPacketWithDatagramID // undecryptable packets, waiting for a change in encryption level
+ undecryptablePacketsToProcess []receivedPacketWithDatagramID
earlyConnReadyChan chan struct{}
sentFirstPacket bool
@@ -220,9 +223,10 @@ type Conn struct {
connStateMutex sync.Mutex
connState ConnectionState
- logID string
- tracer *logging.ConnectionTracer
- logger utils.Logger
+ logID string
+ qlogTrace qlogwriter.Trace
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
}
var _ streamSender = &Conn{}
@@ -259,7 +263,7 @@ var newConnection = func(
tokenGenerator *handshake.TokenGenerator,
clientAddressValidated bool,
rtt time.Duration,
- tracer *logging.ConnectionTracer,
+ qlogTrace qlogwriter.Trace,
logger utils.Logger,
v protocol.Version,
) *wrappedConn {
@@ -273,10 +277,13 @@ var newConnection = func(
tokenGenerator: tokenGenerator,
oneRTTStream: newCryptoStream(),
perspective: protocol.PerspectiveServer,
- tracer: tracer,
+ qlogTrace: qlogTrace,
logger: logger,
version: v,
}
+ if qlogTrace != nil {
+ s.qlogger = qlogTrace.AddProducer()
+ }
if origDestConnID.Len() > 0 {
s.logID = origDestConnID.String()
} else {
@@ -303,15 +310,16 @@ var newConnection = func(
)
s.preSetup()
s.rttStats.SetInitialRTT(rtt)
- s.sentPacketHandler, s.receivedPacketHandler = ackhandler.NewAckHandler(
+ s.sentPacketHandler = ackhandler.NewSentPacketHandler(
0,
protocol.ByteCount(s.config.InitialPacketSize),
s.rttStats,
&s.connStats,
clientAddressValidated,
s.conn.capabilities().ECN,
+ s.receivedPacketHandler.IgnorePacketsBelow,
s.perspective,
- s.tracer,
+ s.qlogger,
s.logger,
)
s.currentMTUEstimate.Store(uint32(estimateMaxPayloadSize(protocol.ByteCount(s.config.InitialPacketSize))))
@@ -344,8 +352,8 @@ var newConnection = func(
} else {
params.MaxDatagramFrameSize = protocol.InvalidByteCount
}
- if s.tracer != nil && s.tracer.SentTransportParameters != nil {
- s.tracer.SentTransportParameters(params)
+ if s.qlogger != nil {
+ s.qlogTransportParameters(params, protocol.PerspectiveServer, false)
}
cs := handshake.NewCryptoSetupServer(
clientDestConnID,
@@ -355,12 +363,12 @@ var newConnection = func(
tlsConf,
conf.Allow0RTT,
s.rttStats,
- tracer,
+ s.qlogger,
logger,
s.version,
)
s.cryptoStreamHandler = cs
- s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, s.receivedPacketHandler, s.datagramQueue, s.perspective)
+ s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, &s.receivedPacketHandler, s.datagramQueue, s.perspective)
s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen)
s.cryptoStreamManager = newCryptoStreamManager(s.initialStream, s.handshakeStream, s.oneRTTStream)
return &wrappedConn{Conn: s}
@@ -380,7 +388,7 @@ var newClientConnection = func(
initialPacketNumber protocol.PacketNumber,
enable0RTT bool,
hasNegotiatedVersion bool,
- tracer *logging.ConnectionTracer,
+ qlogTrace qlogwriter.Trace,
logger utils.Logger,
v protocol.Version,
) *wrappedConn {
@@ -393,10 +401,23 @@ var newClientConnection = func(
perspective: protocol.PerspectiveClient,
logID: destConnID.String(),
logger: logger,
- tracer: tracer,
+ qlogTrace: qlogTrace,
versionNegotiated: hasNegotiatedVersion,
version: v,
}
+ if qlogTrace != nil {
+ s.qlogger = qlogTrace.AddProducer()
+ }
+ if s.qlogger != nil {
+ var srcAddr, destAddr *net.UDPAddr
+ if addr, ok := conn.LocalAddr().(*net.UDPAddr); ok {
+ srcAddr = addr
+ }
+ if addr, ok := conn.RemoteAddr().(*net.UDPAddr); ok {
+ destAddr = addr
+ }
+ s.qlogger.RecordEvent(startedConnectionEvent(srcAddr, destAddr))
+ }
s.connIDManager = newConnIDManager(
destConnID,
func(token protocol.StatelessResetToken) { runner.AddResetToken(token, s) },
@@ -418,15 +439,16 @@ var newClientConnection = func(
)
s.ctx, s.ctxCancel = context.WithCancelCause(ctx)
s.preSetup()
- s.sentPacketHandler, s.receivedPacketHandler = ackhandler.NewAckHandler(
+ s.sentPacketHandler = ackhandler.NewSentPacketHandler(
initialPacketNumber,
protocol.ByteCount(s.config.InitialPacketSize),
s.rttStats,
&s.connStats,
false, // has no effect
s.conn.capabilities().ECN,
+ s.receivedPacketHandler.IgnorePacketsBelow,
s.perspective,
- s.tracer,
+ s.qlogger,
s.logger,
)
s.currentMTUEstimate.Store(uint32(estimateMaxPayloadSize(protocol.ByteCount(s.config.InitialPacketSize))))
@@ -456,8 +478,8 @@ var newClientConnection = func(
} else {
params.MaxDatagramFrameSize = protocol.InvalidByteCount
}
- if s.tracer != nil && s.tracer.SentTransportParameters != nil {
- s.tracer.SentTransportParameters(params)
+ if s.qlogger != nil {
+ s.qlogTransportParameters(params, protocol.PerspectiveClient, false)
}
cs := handshake.NewCryptoSetupClient(
destConnID,
@@ -465,14 +487,14 @@ var newClientConnection = func(
tlsConf,
enable0RTT,
s.rttStats,
- tracer,
+ s.qlogger,
logger,
s.version,
)
s.cryptoStreamHandler = cs
s.cryptoStreamManager = newCryptoStreamManager(s.initialStream, s.handshakeStream, oneRTTStream)
s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen)
- s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, s.receivedPacketHandler, s.datagramQueue, s.perspective)
+ s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, s.initialStream, s.handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, &s.receivedPacketHandler, s.datagramQueue, s.perspective)
if len(tlsConf.ServerName) > 0 {
s.tokenStoreKey = tlsConf.ServerName
} else {
@@ -498,7 +520,7 @@ func (c *Conn) preSetup() {
c.config.EnableStreamResetPartialDelivery,
false, // ACK_FREQUENCY is not supported yet
)
- c.rttStats = &utils.RTTStats{}
+ c.rttStats = utils.NewRTTStats()
c.connFlowController = flowcontrol.NewConnectionFlowController(
protocol.ByteCount(c.config.InitialConnectionReceiveWindow),
protocol.ByteCount(c.config.MaxConnectionReceiveWindow),
@@ -532,6 +554,8 @@ func (c *Conn) preSetup() {
c.lastPacketReceivedTime = now
c.creationTime = now
+ c.receivedPacketHandler = *ackhandler.NewReceivedPacketHandler(c.logger)
+
c.datagramQueue = newDatagramQueue(c.scheduleSending, c.logger)
c.connState.Version = c.version
}
@@ -597,7 +621,7 @@ runLoop:
queue := c.undecryptablePacketsToProcess
c.undecryptablePacketsToProcess = nil
for _, p := range queue {
- processed, err := c.handleOnePacket(p)
+ processed, err := c.handleOnePacket(p.receivedPacket, p.datagramID)
if err != nil {
c.setCloseError(&closeError{err: err})
break runLoop
@@ -652,7 +676,7 @@ runLoop:
// Check for loss detection timeout.
// This could cause packets to be declared lost, and retransmissions to be enqueued.
now := monotime.Now()
- if timeout := c.sentPacketHandler.GetLossDetectionTimeout(); !timeout.IsZero() && timeout.Before(now) {
+ if timeout := c.sentPacketHandler.GetLossDetectionTimeout(); !timeout.IsZero() && !timeout.After(now) {
if err := c.sentPacketHandler.OnLossDetectionTimeout(now); err != nil {
c.setCloseError(&closeError{err: err})
break runLoop
@@ -721,9 +745,9 @@ runLoop:
c.cryptoStreamHandler.Close()
c.sendQueue.Close() // close the send queue before sending the CONNECTION_CLOSE
c.handleCloseError(closeErr)
- if c.tracer != nil && c.tracer.Close != nil {
+ if c.qlogger != nil {
if e := (&errCloseForRecreating{}); !errors.As(closeErr.err, &e) {
- c.tracer.Close()
+ c.qlogger.Close()
}
}
c.logger.Infof("Connection %s closed.", c.logID)
@@ -750,10 +774,16 @@ func (c *Conn) supportsDatagrams() bool {
func (c *Conn) ConnectionState() ConnectionState {
c.connStateMutex.Lock()
defer c.connStateMutex.Unlock()
+
cs := c.cryptoStreamHandler.ConnectionState()
c.connState.TLS = cs.ConnectionState
c.connState.Used0RTT = cs.Used0RTT
- c.connState.SupportsStreamResetPartialDelivery = c.peerParams.EnableResetStreamAt
+ if c.peerParams != nil {
+ c.connState.SupportsDatagrams.Remote = c.supportsDatagrams()
+ c.connState.SupportsStreamResetPartialDelivery.Remote = c.peerParams.EnableResetStreamAt
+ }
+ c.connState.SupportsDatagrams.Local = c.config.EnableDatagrams
+ c.connState.SupportsStreamResetPartialDelivery.Local = c.config.EnableStreamResetPartialDelivery
c.connState.GSO = c.conn.capabilities().GSO
return c.connState
}
@@ -867,9 +897,6 @@ func (c *Conn) maybeResetTimer() {
return
}
- if t := c.connIDGenerator.NextRetireTime(); !t.IsZero() && t.Before(deadline) {
- deadline = t
- }
if !c.pacingDeadline.IsZero() && c.pacingDeadline.Before(deadline) {
deadline = c.pacingDeadline
}
@@ -911,8 +938,10 @@ func (c *Conn) handleHandshakeComplete(now monotime.Time) error {
c.connIDManager.SetHandshakeComplete()
c.connIDGenerator.SetHandshakeComplete(now.Add(3 * c.rttStats.PTO(false)))
- if c.tracer != nil && c.tracer.ChoseALPN != nil {
- c.tracer.ChoseALPN(c.cryptoStreamHandler.ConnectionState().NegotiatedProtocol)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.ALPNInformation{
+ ChosenALPN: c.cryptoStreamHandler.ConnectionState().NegotiatedProtocol,
+ })
}
// The server applies transport parameters right away, but the client side has to wait for handshake completion.
@@ -969,41 +998,48 @@ func (c *Conn) handleHandshakeConfirmed(now monotime.Time) error {
return nil
}
+const maxPacketsToProcess = 32
+
func (c *Conn) handlePackets() (wasProcessed bool, _ error) {
- // Now process all packets in the receivedPackets channel.
- // Limit the number of packets to the length of the receivedPackets channel,
+ // Process packets from the receivedPackets queue.
+ // Limit the number of packets to process to maxPacketsToProcess,
// so we eventually get a chance to send out an ACK when receiving a lot of packets.
c.receivedPacketMx.Lock()
- numPackets := c.receivedPackets.Len()
- if numPackets == 0 {
+
+ if c.receivedPackets.Empty() {
c.receivedPacketMx.Unlock()
return false, nil
}
var hasMorePackets bool
- for i := 0; i < numPackets; i++ {
- if i > 0 {
- c.receivedPacketMx.Lock()
- }
+ for range maxPacketsToProcess {
p := c.receivedPackets.PopFront()
- hasMorePackets = !c.receivedPackets.Empty()
c.receivedPacketMx.Unlock()
- processed, err := c.handleOnePacket(p)
+ var datagramID qlog.DatagramID
+ if c.qlogger != nil && wire.IsLongHeaderPacket(p.data[0]) {
+ datagramID = qlog.CalculateDatagramID(p.data)
+ }
+ processed, err := c.handleOnePacket(p, datagramID)
if err != nil {
return false, err
}
if processed {
wasProcessed = true
}
+ c.receivedPacketMx.Lock()
+ hasMorePackets = !c.receivedPackets.Empty()
if !hasMorePackets {
break
}
- // only process a single packet at a time before handshake completion
- if !c.handshakeComplete {
+ // Prioritize sending of new CRYPTO data.
+ // This is especially relevant when processing 0-RTT packets.
+ if !c.handshakeComplete && (c.initialStream.HasData() || c.handshakeStream.HasData()) {
break
}
}
+ c.receivedPacketMx.Unlock()
+
if hasMorePackets {
select {
case c.notifyReceivedPacket <- struct{}{}:
@@ -1013,12 +1049,11 @@ func (c *Conn) handlePackets() (wasProcessed bool, _ error) {
return wasProcessed, nil
}
-func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
+func (c *Conn) handleOnePacket(rp receivedPacket, datagramID qlog.DatagramID) (wasProcessed bool, _ error) {
c.sentPacketHandler.ReceivedBytes(rp.Size(), rp.rcvTime)
if wire.IsVersionNegotiationPacket(rp.data) {
- c.handleVersionNegotiationPacket(rp)
- return false, nil
+ return false, c.handleVersionNegotiationPacket(rp)
}
var counter uint8
@@ -1032,15 +1067,24 @@ func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
destConnID, err := wire.ParseConnectionID(p.data, c.srcConnIDLen)
if err != nil {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropHeaderParseError)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
}
c.logger.Debugf("error parsing packet, couldn't parse connection ID: %s", err)
break
}
if destConnID != lastConnID {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnknownConnectionID)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{DestConnectionID: destConnID},
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnknownConnectionID,
+ })
}
c.logger.Debugf("coalesced packet has different destination connection ID: %s, expected %s", destConnID, lastConnID)
break
@@ -1050,12 +1094,21 @@ func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
if wire.IsLongHeaderPacket(p.data[0]) {
hdr, packetData, rest, err := wire.ParsePacket(p.data)
if err != nil {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- dropReason := logging.PacketDropHeaderParseError
+ if c.qlogger != nil {
if err == wire.ErrUnsupportedVersion {
- dropReason = logging.PacketDropUnsupportedVersion
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{Version: hdr.Version},
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnsupportedVersion,
+ })
+ } else {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
}
- c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), dropReason)
}
c.logger.Debugf("error parsing packet: %s", err)
break
@@ -1063,8 +1116,12 @@ func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
lastConnID = hdr.DestConnectionID
if hdr.Version != c.version {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedVersion)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: len(data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnexpectedVersion,
+ })
}
c.logger.Debugf("Dropping packet with version %x. Expected %x.", hdr.Version, c.version)
break
@@ -1082,7 +1139,7 @@ func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
p.data = packetData
- processed, err := c.handleLongHeaderPacket(p, hdr)
+ processed, err := c.handleLongHeaderPacket(p, hdr, datagramID)
if err != nil {
return false, err
}
@@ -1094,7 +1151,7 @@ func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
if counter > 0 {
p.buffer.Split()
}
- processed, err := c.handleShortHeaderPacket(p, counter > 0)
+ processed, err := c.handleShortHeaderPacket(p, counter > 0, datagramID)
if err != nil {
return false, err
}
@@ -1110,7 +1167,11 @@ func (c *Conn) handleOnePacket(rp receivedPacket) (wasProcessed bool, _ error) {
return wasProcessed, nil
}
-func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasProcessed bool, _ error) {
+func (c *Conn) handleShortHeaderPacket(
+ p receivedPacket,
+ isCoalesced bool,
+ datagramID qlog.DatagramID, // only for logging
+) (wasProcessed bool, _ error) {
var wasQueued bool
defer func() {
@@ -1122,7 +1183,15 @@ func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasP
destConnID, err := wire.ParseConnectionID(p.data, c.srcConnIDLen)
if err != nil {
- c.tracer.DroppedPacket(logging.PacketType1RTT, protocol.InvalidPacketNumber, protocol.ByteCount(len(p.data)), logging.PacketDropHeaderParseError)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: len(p.data)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
return false, nil
}
pn, pnLen, keyPhase, data, err := c.unpacker.UnpackShortHeader(p.rcvTime, p.data)
@@ -1138,7 +1207,7 @@ func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasP
return false, &StatelessResetError{}
}
}
- wasQueued, err = c.handleUnpackError(err, p, logging.PacketType1RTT)
+ wasQueued, err = c.handleUnpackError(err, p, qlog.PacketType1RTT, datagramID)
return false, err
}
c.largestRcvdAppData = max(c.largestRcvdAppData, pn)
@@ -1150,26 +1219,38 @@ func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasP
if c.receivedPacketHandler.IsPotentiallyDuplicate(pn, protocol.Encryption1RTT) {
c.logger.Debugf("Dropping (potentially) duplicate packet.")
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketType1RTT, pn, p.Size(), logging.PacketDropDuplicate)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ PacketNumber: pn,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDuplicate,
+ })
}
return false, nil
}
- var log func([]logging.Frame)
- if c.tracer != nil && c.tracer.ReceivedShortHeaderPacket != nil {
- log = func(frames []logging.Frame) {
- c.tracer.ReceivedShortHeaderPacket(
- &logging.ShortHeader{
+ var log func([]qlog.Frame)
+ if c.qlogger != nil {
+ log = func(frames []qlog.Frame) {
+ c.qlogger.RecordEvent(qlog.PacketReceived{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
DestConnectionID: destConnID,
PacketNumber: pn,
- PacketNumberLen: pnLen,
- KeyPhase: keyPhase,
+ KeyPhaseBit: keyPhase,
},
- p.Size(),
- p.ecn,
- frames,
- )
+ Raw: qlog.RawInfo{
+ Length: int(p.Size()),
+ PayloadLength: int(p.Size() - wire.ShortHeaderLen(destConnID, pnLen)),
+ },
+ DatagramID: datagramID,
+ Frames: frames,
+ ECN: toQlogECN(p.ecn),
+ })
}
}
isNonProbing, pathChallenge, err := c.handleUnpackedShortHeaderPacket(destConnID, pn, data, p.ecn, p.rcvTime, log)
@@ -1200,7 +1281,7 @@ func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasP
return true, err
}
c.logger.Debugf("sending path probe packet to %s", p.remoteAddr)
- c.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false)
+ c.logShortHeaderPacketWithDatagramID(probe, protocol.ECNNon, buf.Len(), false, datagramID)
c.registerPackedShortHeaderPacket(probe, protocol.ECNNon, p.rcvTime)
c.sendQueue.SendProbe(buf, p.remoteAddr)
}
@@ -1224,7 +1305,7 @@ func (c *Conn) handleShortHeaderPacket(p receivedPacket, isCoalesced bool) (wasP
return true, nil
}
-func (c *Conn) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header) (wasProcessed bool, _ error) {
+func (c *Conn) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header, datagramID qlog.DatagramID) (wasProcessed bool, _ error) {
var wasQueued bool
defer func() {
@@ -1241,23 +1322,39 @@ func (c *Conn) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header) (wasPr
// The server can change the source connection ID with the first Handshake packet.
// After this, all packets with a different source connection have to be ignored.
if c.receivedFirstPacket && hdr.Type == protocol.PacketTypeInitial && hdr.SrcConnectionID != c.handshakeDestConnID {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeInitial, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnknownConnectionID)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeInitial,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnknownConnectionID,
+ })
}
c.logger.Debugf("Dropping Initial packet (%d bytes) with unexpected source connection ID: %s (expected %s)", p.Size(), hdr.SrcConnectionID, c.handshakeDestConnID)
return false, nil
}
// drop 0-RTT packets, if we are a client
if c.perspective == protocol.PerspectiveClient && hdr.Type == protocol.PacketType0RTT {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketType0RTT, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedPacket)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType0RTT,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
}
return false, nil
}
packet, err := c.unpacker.UnpackLongHeader(hdr, p.data)
if err != nil {
- wasQueued, err = c.handleUnpackError(err, p, logging.PacketTypeFromHeader(hdr))
+ wasQueued, err = c.handleUnpackError(err, p, toQlogPacketType(hdr.Type), datagramID)
return false, err
}
@@ -1268,30 +1365,51 @@ func (c *Conn) handleLongHeaderPacket(p receivedPacket, hdr *wire.Header) (wasPr
if pn := packet.hdr.PacketNumber; c.receivedPacketHandler.IsPotentiallyDuplicate(pn, packet.encryptionLevel) {
c.logger.Debugf("Dropping (potentially) duplicate packet.")
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeFromHeader(hdr), pn, p.Size(), logging.PacketDropDuplicate)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: toQlogPacketType(packet.hdr.Type),
+ DestConnectionID: hdr.DestConnectionID,
+ SrcConnectionID: hdr.SrcConnectionID,
+ PacketNumber: pn,
+ Version: packet.hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size()), PayloadLength: int(packet.hdr.Length)},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDuplicate,
+ })
}
return false, nil
}
- if err := c.handleUnpackedLongHeaderPacket(packet, p.ecn, p.rcvTime, p.Size()); err != nil {
+ if err := c.handleUnpackedLongHeaderPacket(packet, p.ecn, p.rcvTime, datagramID, p.Size()); err != nil {
return false, err
}
return true, nil
}
-func (c *Conn) handleUnpackError(err error, p receivedPacket, pt logging.PacketType) (wasQueued bool, _ error) {
+func (c *Conn) handleUnpackError(err error, p receivedPacket, pt qlog.PacketType, datagramID qlog.DatagramID) (wasQueued bool, _ error) {
switch err {
case handshake.ErrKeysDropped:
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropKeyUnavailable)
+ if c.qlogger != nil {
+ connID, _ := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ DestConnectionID: connID,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropKeyUnavailable,
+ })
}
c.logger.Debugf("Dropping %s packet (%d bytes) because we already dropped the keys.", pt, p.Size())
return false, nil
case handshake.ErrKeysNotYetAvailable:
// Sealer for this encryption level not yet available.
// Try again later.
- c.tryQueueingUndecryptablePacket(p, pt)
+ c.tryQueueingUndecryptablePacket(p, pt, datagramID)
return true, nil
case wire.ErrInvalidReservedBits:
return false, &qerr.TransportError{
@@ -1300,8 +1418,18 @@ func (c *Conn) handleUnpackError(err error, p receivedPacket, pt logging.PacketT
}
case handshake.ErrDecryptionFailed:
// This might be a packet injected by an attacker. Drop it.
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropPayloadDecryptError)
+ if c.qlogger != nil {
+ connID, _ := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ DestConnectionID: connID,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropPayloadDecryptError,
+ })
}
c.logger.Debugf("Dropping %s packet (%d bytes) that could not be unpacked. Error: %s", pt, p.Size(), err)
return false, nil
@@ -1309,8 +1437,18 @@ func (c *Conn) handleUnpackError(err error, p receivedPacket, pt logging.PacketT
var headerErr *headerParseError
if errors.As(err, &headerErr) {
// This might be a packet injected by an attacker. Drop it.
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropHeaderParseError)
+ if c.qlogger != nil {
+ connID, _ := wire.ParseConnectionID(p.data, c.srcConnIDLen)
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ DestConnectionID: connID,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
}
c.logger.Debugf("Dropping %s packet (%d bytes) for which we couldn't unpack the header. Error: %s", pt, p.Size(), err)
return false, nil
@@ -1323,23 +1461,50 @@ func (c *Conn) handleUnpackError(err error, p receivedPacket, pt logging.PacketT
func (c *Conn) handleRetryPacket(hdr *wire.Header, data []byte, rcvTime monotime.Time) bool /* was this a valid Retry */ {
if c.perspective == protocol.PerspectiveServer {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
}
c.logger.Debugf("Ignoring Retry.")
return false
}
if c.receivedFirstPacket {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
}
c.logger.Debugf("Ignoring Retry, since we already received a packet.")
return false
}
destConnID := c.connIDManager.Get()
if hdr.SrcConnectionID == destConnID {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropUnexpectedPacket)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
}
c.logger.Debugf("Ignoring Retry, since the server didn't change the Source Connection ID.")
return false
@@ -1353,8 +1518,17 @@ func (c *Conn) handleRetryPacket(hdr *wire.Header, data []byte, rcvTime monotime
tag := handshake.GetRetryIntegrityTag(data[:len(data)-16], destConnID, hdr.Version)
if !bytes.Equal(data[len(data)-16:], tag[:]) {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeRetry, protocol.InvalidPacketNumber, protocol.ByteCount(len(data)), logging.PacketDropPayloadDecryptError)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ SrcConnectionID: hdr.SrcConnectionID,
+ DestConnectionID: hdr.DestConnectionID,
+ Version: hdr.Version,
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ Trigger: qlog.PacketDropPayloadDecryptError,
+ })
}
c.logger.Debugf("Ignoring spoofed Retry. Integrity Tag doesn't match.")
return false
@@ -1374,44 +1548,71 @@ func (c *Conn) handleRetryPacket(hdr *wire.Header, data []byte, rcvTime monotime
(&wire.ExtendedHeader{Header: *hdr}).Log(c.logger)
c.logger.Debugf("Switching destination connection ID to: %s", hdr.SrcConnectionID)
}
- if c.tracer != nil && c.tracer.ReceivedRetry != nil {
- c.tracer.ReceivedRetry(hdr)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketReceived{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketTypeRetry,
+ DestConnectionID: destConnID,
+ SrcConnectionID: newDestConnID,
+ Version: hdr.Version,
+ Token: &qlog.Token{Raw: hdr.Token},
+ },
+ Raw: qlog.RawInfo{Length: len(data)},
+ })
}
c.scheduleSending()
return true
}
-func (c *Conn) handleVersionNegotiationPacket(p receivedPacket) {
+func (c *Conn) handleVersionNegotiationPacket(p receivedPacket) error {
if c.perspective == protocol.PerspectiveServer || // servers never receive version negotiation packets
c.receivedFirstPacket || c.versionNegotiated { // ignore delayed / duplicated version negotiation packets
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedPacket)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedPacket,
+ })
}
- return
+ return nil
}
src, dest, supportedVersions, err := wire.ParseVersionNegotiationPacket(p.data)
if err != nil {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropHeaderParseError)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropHeaderParseError,
+ })
}
c.logger.Debugf("Error parsing Version Negotiation packet: %s", err)
- return
+ return nil
}
if slices.Contains(supportedVersions, c.version) {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeVersionNegotiation, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropUnexpectedVersion)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{PacketType: qlog.PacketTypeVersionNegotiation},
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ Trigger: qlog.PacketDropUnexpectedVersion,
+ })
}
// The Version Negotiation packet contains the version that we offered.
// This might be a packet sent by an attacker, or it was corrupted.
- return
+ return nil
}
c.logger.Infof("Received a Version Negotiation packet. Supported Versions: %s", supportedVersions)
- if c.tracer != nil && c.tracer.ReceivedVersionNegotiationPacket != nil {
- c.tracer.ReceivedVersionNegotiationPacket(dest, src, supportedVersions)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.VersionNegotiationReceived{
+ Header: qlog.PacketHeaderVersionNegotiation{
+ DestConnectionID: dest,
+ SrcConnectionID: src,
+ },
+ SupportedVersions: supportedVersions,
+ })
}
newVersion, ok := protocol.ChooseSupportedVersion(c.config.Versions, supportedVersions)
if !ok {
@@ -1420,37 +1621,46 @@ func (c *Conn) handleVersionNegotiationPacket(p receivedPacket) {
Theirs: supportedVersions,
})
c.logger.Infof("No compatible QUIC version found.")
- return
+ return nil
}
- if c.tracer != nil && c.tracer.NegotiatedVersion != nil {
- c.tracer.NegotiatedVersion(newVersion, c.config.Versions, supportedVersions)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.VersionInformation{
+ ChosenVersion: newVersion,
+ ClientVersions: c.config.Versions,
+ ServerVersions: supportedVersions,
+ })
}
c.logger.Infof("Switching to QUIC version %s.", newVersion)
nextPN, _ := c.sentPacketHandler.PeekPacketNumber(protocol.EncryptionInitial)
- c.destroyImpl(&errCloseForRecreating{
+ return &errCloseForRecreating{
nextPacketNumber: nextPN,
nextVersion: newVersion,
- })
+ }
}
func (c *Conn) handleUnpackedLongHeaderPacket(
packet *unpackedPacket,
ecn protocol.ECN,
rcvTime monotime.Time,
+ datagramID qlog.DatagramID, // only for logging
packetSize protocol.ByteCount, // only for logging
) error {
if !c.receivedFirstPacket {
c.receivedFirstPacket = true
- if !c.versionNegotiated && c.tracer != nil && c.tracer.NegotiatedVersion != nil {
- var clientVersions, serverVersions []protocol.Version
+ if !c.versionNegotiated && c.qlogger != nil {
+ var clientVersions, serverVersions []Version
switch c.perspective {
case protocol.PerspectiveClient:
clientVersions = c.config.Versions
case protocol.PerspectiveServer:
serverVersions = c.config.Versions
}
- c.tracer.NegotiatedVersion(c.version, clientVersions, serverVersions)
+ c.qlogger.RecordEvent(qlog.VersionInformation{
+ ChosenVersion: c.version,
+ ClientVersions: clientVersions,
+ ServerVersions: serverVersions,
+ })
}
// The server can change the source connection ID with the first Handshake packet.
if c.perspective == protocol.PerspectiveClient && packet.hdr.SrcConnectionID != c.handshakeDestConnID {
@@ -1469,13 +1679,15 @@ func (c *Conn) handleUnpackedLongHeaderPacket(
c.handshakeDestConnID = packet.hdr.SrcConnectionID
c.connIDManager.ChangeInitialConnID(packet.hdr.SrcConnectionID)
}
- if c.tracer != nil && c.tracer.StartedConnection != nil {
- c.tracer.StartedConnection(
- c.conn.LocalAddr(),
- c.conn.RemoteAddr(),
- packet.hdr.SrcConnectionID,
- packet.hdr.DestConnectionID,
- )
+ if c.qlogger != nil {
+ var srcAddr, destAddr *net.UDPAddr
+ if addr, ok := c.conn.LocalAddr().(*net.UDPAddr); ok {
+ srcAddr = addr
+ }
+ if addr, ok := c.conn.RemoteAddr().(*net.UDPAddr); ok {
+ destAddr = addr
+ }
+ c.qlogger.RecordEvent(startedConnectionEvent(srcAddr, destAddr))
}
}
}
@@ -1497,16 +1709,37 @@ func (c *Conn) handleUnpackedLongHeaderPacket(
c.largestRcvdAppData = max(c.largestRcvdAppData, packet.hdr.PacketNumber)
}
- var log func([]logging.Frame)
- if c.tracer != nil && c.tracer.ReceivedLongHeaderPacket != nil {
- log = func(frames []logging.Frame) {
- c.tracer.ReceivedLongHeaderPacket(packet.hdr, packetSize, ecn, frames)
+ var log func([]qlog.Frame)
+ if c.qlogger != nil {
+ log = func(frames []qlog.Frame) {
+ var token *qlog.Token
+ if len(packet.hdr.Token) > 0 {
+ token = &qlog.Token{Raw: packet.hdr.Token}
+ }
+ c.qlogger.RecordEvent(qlog.PacketReceived{
+ Header: qlog.PacketHeader{
+ PacketType: toQlogPacketType(packet.hdr.Type),
+ DestConnectionID: packet.hdr.DestConnectionID,
+ SrcConnectionID: packet.hdr.SrcConnectionID,
+ PacketNumber: packet.hdr.PacketNumber,
+ Version: packet.hdr.Version,
+ Token: token,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(packetSize),
+ PayloadLength: int(packet.hdr.Length),
+ },
+ DatagramID: datagramID,
+ Frames: frames,
+ ECN: toQlogECN(ecn),
+ })
}
}
isAckEliciting, _, _, err := c.handleFrames(packet.data, packet.hdr.DestConnectionID, packet.encryptionLevel, log, rcvTime)
if err != nil {
return err
}
+ c.sentPacketHandler.ReceivedPacket(packet.encryptionLevel, rcvTime)
return c.receivedPacketHandler.ReceivedPacket(packet.hdr.PacketNumber, ecn, packet.encryptionLevel, rcvTime, isAckEliciting)
}
@@ -1516,7 +1749,7 @@ func (c *Conn) handleUnpackedShortHeaderPacket(
data []byte,
ecn protocol.ECN,
rcvTime monotime.Time,
- log func([]logging.Frame),
+ log func([]qlog.Frame),
) (isNonProbing bool, pathChallenge *wire.PathChallengeFrame, _ error) {
c.lastPacketReceivedTime = rcvTime
c.firstAckElicitingPacketAfterIdleSentTime = 0
@@ -1526,6 +1759,7 @@ func (c *Conn) handleUnpackedShortHeaderPacket(
if err != nil {
return false, nil, err
}
+ c.sentPacketHandler.ReceivedPacket(protocol.Encryption1RTT, rcvTime)
if err := c.receivedPacketHandler.ReceivedPacket(pn, ecn, protocol.Encryption1RTT, rcvTime, isAckEliciting); err != nil {
return false, nil, err
}
@@ -1538,14 +1772,14 @@ func (c *Conn) handleFrames(
data []byte,
destConnID protocol.ConnectionID,
encLevel protocol.EncryptionLevel,
- log func([]logging.Frame),
+ log func([]qlog.Frame),
rcvTime monotime.Time,
) (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
+ var frames []qlog.Frame
if log != nil {
- frames = make([]logging.Frame, 0, 4)
+ frames = make([]qlog.Frame, 0, 4)
}
handshakeWasComplete := c.handshakeComplete
var handleErr error
@@ -1580,7 +1814,7 @@ func (c *Conn) handleFrames(
data = data[l:]
if log != nil {
- frames = append(frames, toLoggingFrame(streamFrame))
+ frames = append(frames, toQlogFrame(streamFrame))
}
// an error occurred handling a previous frame, don't handle the current frame
if skipHandling {
@@ -1595,7 +1829,7 @@ func (c *Conn) handleFrames(
}
data = data[l:]
if log != nil {
- frames = append(frames, toLoggingFrame(ackFrame))
+ frames = append(frames, toQlogFrame(ackFrame))
}
// an error occurred handling a previous frame, don't handle the current frame
if skipHandling {
@@ -1611,7 +1845,7 @@ func (c *Conn) handleFrames(
data = data[l:]
if log != nil {
- frames = append(frames, toLoggingFrame(datagramFrame))
+ frames = append(frames, toQlogFrame(datagramFrame))
}
// an error occurred handling a previous frame, don't handle the current frame
if skipHandling {
@@ -1627,7 +1861,7 @@ func (c *Conn) handleFrames(
data = data[l:]
if log != nil {
- frames = append(frames, toLoggingFrame(frame))
+ frames = append(frames, toQlogFrame(frame))
}
// an error occurred handling a previous frame, don't handle the current frame
if skipHandling {
@@ -1721,8 +1955,16 @@ func (c *Conn) handlePacket(p receivedPacket) {
// Discard packets once the amount of queued packets is larger than
// the channel size, protocol.MaxConnUnprocessedPackets
if c.receivedPackets.Len() >= protocol.MaxConnUnprocessedPackets {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(logging.PacketTypeNotDetermined, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropDOSPrevention)
+ if c.qlogger != nil {
+ var datagramID qlog.DatagramID
+ if wire.IsLongHeaderPacket(p.data[0]) {
+ datagramID = qlog.CalculateDatagramID(p.data)
+ }
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
}
c.receivedPacketMx.Unlock()
return
@@ -1974,23 +2216,38 @@ func (c *Conn) handleCloseError(closeErr *closeError) {
transportErr *TransportError
)
var isRemoteClose bool
+ var trigger qlog.ConnectionCloseTrigger
+ var reason string
+ var transportErrorCode *qlog.TransportErrorCode
+ var applicationErrorCode *qlog.ApplicationErrorCode
switch {
case errors.Is(e, qerr.ErrIdleTimeout),
- errors.Is(e, qerr.ErrHandshakeTimeout),
- errors.As(e, &statelessResetErr),
- errors.As(e, &versionNegotiationErr),
- errors.As(e, &recreateErr):
+ errors.Is(e, qerr.ErrHandshakeTimeout):
+ trigger = qlog.ConnectionCloseTriggerIdleTimeout
+ case errors.As(e, &statelessResetErr):
+ trigger = qlog.ConnectionCloseTriggerStatelessReset
+ case errors.As(e, &versionNegotiationErr):
+ trigger = qlog.ConnectionCloseTriggerVersionMismatch
+ case errors.As(e, &recreateErr):
case errors.As(e, &applicationErr):
isRemoteClose = applicationErr.Remote
+ reason = applicationErr.ErrorMessage
+ applicationErrorCode = &applicationErr.ErrorCode
case errors.As(e, &transportErr):
isRemoteClose = transportErr.Remote
+ reason = transportErr.ErrorMessage
+ transportErrorCode = &transportErr.ErrorCode
case closeErr.immediate:
e = closeErr.err
default:
- e = &qerr.TransportError{
+ te := &qerr.TransportError{
ErrorCode: qerr.InternalError,
ErrorMessage: e.Error(),
}
+ e = te
+ reason = te.ErrorMessage
+ code := te.ErrorCode
+ transportErrorCode = &code
}
c.streamsMap.CloseWithError(e)
@@ -2004,8 +2261,18 @@ func (c *Conn) handleCloseError(closeErr *closeError) {
// handler map when it is closed, so we need to make sure that this happens last.
defer c.connIDManager.Close()
- if c.tracer != nil && c.tracer.ClosedConnection != nil && !errors.As(e, &recreateErr) {
- c.tracer.ClosedConnection(e)
+ if c.qlogger != nil && !errors.As(e, &recreateErr) {
+ initiator := qlog.InitiatorLocal
+ if isRemoteClose {
+ initiator = qlog.InitiatorRemote
+ }
+ c.qlogger.RecordEvent(qlog.ConnectionClosed{
+ Initiator: initiator,
+ ConnectionError: transportErrorCode,
+ ApplicationError: applicationErrorCode,
+ Trigger: trigger,
+ Reason: reason,
+ })
}
// If this is a remote close we're done here
@@ -2031,9 +2298,6 @@ func (c *Conn) handleCloseError(closeErr *closeError) {
}
func (c *Conn) dropEncryptionLevel(encLevel protocol.EncryptionLevel, now monotime.Time) error {
- if c.tracer != nil && c.tracer.DroppedEncryptionLevel != nil {
- c.tracer.DroppedEncryptionLevel(encLevel)
- }
c.sentPacketHandler.DropPackets(encLevel, now)
c.receivedPacketHandler.DropPackets(encLevel)
//nolint:exhaustive // only Initial and 0-RTT need special treatment
@@ -2054,22 +2318,41 @@ func (c *Conn) restoreTransportParameters(params *wire.TransportParameters) {
if c.logger.Debug() {
c.logger.Debugf("Restoring Transport Parameters: %s", params)
}
- if c.tracer != nil && c.tracer.RestoredTransportParameters != nil {
- c.tracer.RestoredTransportParameters(params)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.ParametersSet{
+ Restore: true,
+ Initiator: qlog.InitiatorRemote,
+ SentBy: c.perspective,
+ OriginalDestinationConnectionID: params.OriginalDestinationConnectionID,
+ InitialSourceConnectionID: params.InitialSourceConnectionID,
+ RetrySourceConnectionID: params.RetrySourceConnectionID,
+ StatelessResetToken: params.StatelessResetToken,
+ DisableActiveMigration: params.DisableActiveMigration,
+ MaxIdleTimeout: params.MaxIdleTimeout,
+ MaxUDPPayloadSize: params.MaxUDPPayloadSize,
+ AckDelayExponent: params.AckDelayExponent,
+ MaxAckDelay: params.MaxAckDelay,
+ ActiveConnectionIDLimit: params.ActiveConnectionIDLimit,
+ InitialMaxData: params.InitialMaxData,
+ InitialMaxStreamDataBidiLocal: params.InitialMaxStreamDataBidiLocal,
+ InitialMaxStreamDataBidiRemote: params.InitialMaxStreamDataBidiRemote,
+ InitialMaxStreamDataUni: params.InitialMaxStreamDataUni,
+ InitialMaxStreamsBidi: int64(params.MaxBidiStreamNum),
+ InitialMaxStreamsUni: int64(params.MaxUniStreamNum),
+ MaxDatagramFrameSize: params.MaxDatagramFrameSize,
+ EnableResetStreamAt: params.EnableResetStreamAt,
+ })
}
c.peerParams = params
c.connIDGenerator.SetMaxActiveConnIDs(params.ActiveConnectionIDLimit)
c.connFlowController.UpdateSendWindow(params.InitialMaxData)
c.streamsMap.HandleTransportParameters(params)
- c.connStateMutex.Lock()
- c.connState.SupportsDatagrams = c.supportsDatagrams()
- c.connStateMutex.Unlock()
}
func (c *Conn) handleTransportParameters(params *wire.TransportParameters) error {
- if c.tracer != nil && c.tracer.ReceivedTransportParameters != nil {
- c.tracer.ReceivedTransportParameters(params)
+ if c.qlogger != nil {
+ c.qlogTransportParameters(params, c.perspective.Opposite(), false)
}
if err := c.checkTransportParameters(params); err != nil {
return &qerr.TransportError{
@@ -2094,10 +2377,6 @@ func (c *Conn) handleTransportParameters(params *wire.TransportParameters) error
// the client's transport parameters.
close(c.earlyConnReadyChan)
}
-
- c.connStateMutex.Lock()
- c.connState.SupportsDatagrams = c.supportsDatagrams()
- c.connStateMutex.Unlock()
return nil
}
@@ -2161,7 +2440,7 @@ func (c *Conn) applyTransportParameters() {
c.rttStats,
protocol.ByteCount(c.config.InitialPacketSize),
maxPacketSize,
- c.tracer,
+ c.qlogger,
)
}
@@ -2215,7 +2494,7 @@ func (c *Conn) sendPackets(now monotime.Time) error {
return err
}
c.logger.Debugf("sending path probe packet from %s", c.LocalAddr())
- c.logShortHeaderPacket(probe.DestConnID, probe.Ack, probe.Frames, probe.StreamFrames, probe.PacketNumber, probe.PacketNumberLen, probe.KeyPhase, protocol.ECNNon, buf.Len(), false)
+ c.logShortHeaderPacket(probe, protocol.ECNNon, buf.Len())
c.registerPackedShortHeaderPacket(probe, protocol.ECNNon, now)
tr.WriteTo(buf.Data, c.conn.RemoteAddr())
// There's (likely) more data to send. Loop around again.
@@ -2236,7 +2515,7 @@ func (c *Conn) sendPackets(now monotime.Time) error {
return err
}
ecn := c.sentPacketHandler.ECNMode(true)
- c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, buf.Len(), false)
+ c.logShortHeaderPacket(p, ecn, buf.Len())
c.registerPackedShortHeaderPacket(p, ecn, now)
c.sendQueue.Send(buf, 0, ecn)
// There's (likely) more data to send. Loop around again.
@@ -2405,7 +2684,7 @@ func (c *Conn) maybeSendAckOnlyPacket(now monotime.Time) error {
}
return err
}
- c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, buf.Len(), false)
+ c.logShortHeaderPacket(p, ecn, buf.Len())
c.registerPackedShortHeaderPacket(p, ecn, now)
c.sendQueue.Send(buf, 0, ecn)
return nil
@@ -2459,7 +2738,7 @@ func (c *Conn) appendOneShortHeaderPacket(buf *packetBuffer, maxSize protocol.By
return 0, err
}
size := buf.Len() - startLen
- c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, size, false)
+ c.logShortHeaderPacket(p, ecn, size)
c.registerPackedShortHeaderPacket(p, ecn, now)
return size, nil
}
@@ -2678,23 +2957,38 @@ func (c *Conn) scheduleSending() {
}
// tryQueueingUndecryptablePacket queues a packet for which we're missing the decryption keys.
-// The logging.PacketType is only used for logging purposes.
-func (c *Conn) tryQueueingUndecryptablePacket(p receivedPacket, pt logging.PacketType) {
+// The qlogevents.PacketType is only used for logging purposes.
+func (c *Conn) tryQueueingUndecryptablePacket(p receivedPacket, pt qlog.PacketType, datagramID qlog.DatagramID) {
if c.handshakeComplete {
panic("shouldn't queue undecryptable packets after handshake completion")
}
if len(c.undecryptablePackets)+1 > protocol.MaxUndecryptablePackets {
- if c.tracer != nil && c.tracer.DroppedPacket != nil {
- c.tracer.DroppedPacket(pt, protocol.InvalidPacketNumber, p.Size(), logging.PacketDropDOSPrevention)
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketDropped{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ Trigger: qlog.PacketDropDOSPrevention,
+ })
}
c.logger.Infof("Dropping undecryptable packet (%d bytes). Undecryptable packet queue full.", p.Size())
return
}
c.logger.Infof("Queueing packet (%d bytes) for later decryption", p.Size())
- if c.tracer != nil && c.tracer.BufferedPacket != nil {
- c.tracer.BufferedPacket(pt, p.Size())
+ if c.qlogger != nil {
+ c.qlogger.RecordEvent(qlog.PacketBuffered{
+ Header: qlog.PacketHeader{
+ PacketType: pt,
+ PacketNumber: protocol.InvalidPacketNumber,
+ },
+ Raw: qlog.RawInfo{Length: int(p.Size())},
+ DatagramID: datagramID,
+ })
}
- c.undecryptablePackets = append(c.undecryptablePackets, p)
+ c.undecryptablePackets = append(c.undecryptablePackets, receivedPacketWithDatagramID{receivedPacket: p, datagramID: datagramID})
}
func (c *Conn) queueControlFrame(f wire.Frame) {
@@ -2819,6 +3113,19 @@ func (c *Conn) HandshakeComplete() <-chan struct{} {
return c.handshakeCompleteChan
}
+// QlogTrace returns the qlog trace of the QUIC connection.
+// It is nil if qlog is not enabled.
+func (c *Conn) QlogTrace() qlogwriter.Trace {
+ return c.qlogTrace
+}
+
+// NextConnection transitions a connection to be usable after a 0-RTT rejection.
+// It waits for the handshake to complete and then enables the connection for normal use.
+// This should be called when the server rejects 0-RTT and the application receives
+// [Err0RTTRejected] errors.
+//
+// Note that 0-RTT rejection invalidates all data sent in 0-RTT packets. It is the
+// application's responsibility to handle this (for example by resending the data).
func (c *Conn) NextConnection(ctx context.Context) (*Conn, 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/connection_logging.go b/vendor/github.com/quic-go/quic-go/connection_logging.go
index 5ea12d130c..c828c8be02 100644
--- a/vendor/github.com/quic-go/quic-go/connection_logging.go
+++ b/vendor/github.com/quic-go/quic-go/connection_logging.go
@@ -1,46 +1,53 @@
package quic
import (
+ "net"
+ "net/netip"
"slices"
- "github.com/quic-go/quic-go/internal/ackhandler"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/wire"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
)
// ConvertFrame converts a wire.Frame into a logging.Frame.
// This makes it possible for external packages to access the frames.
// Furthermore, it removes the data slices from CRYPTO and STREAM frames.
-func toLoggingFrame(frame wire.Frame) logging.Frame {
+func toQlogFrame(frame wire.Frame) qlog.Frame {
switch f := frame.(type) {
case *wire.AckFrame:
// We use a pool for ACK frames.
// Implementations of the tracer interface may hold on to frames, so we need to make a copy here.
- return toLoggingAckFrame(f)
+ return qlog.Frame{Frame: toQlogAckFrame(f)}
case *wire.CryptoFrame:
- return &logging.CryptoFrame{
- Offset: f.Offset,
- Length: protocol.ByteCount(len(f.Data)),
+ return qlog.Frame{
+ Frame: &qlog.CryptoFrame{
+ Offset: int64(f.Offset),
+ Length: int64(len(f.Data)),
+ },
}
case *wire.StreamFrame:
- return &logging.StreamFrame{
- StreamID: f.StreamID,
- Offset: f.Offset,
- Length: f.DataLen(),
- Fin: f.Fin,
+ return qlog.Frame{
+ Frame: &qlog.StreamFrame{
+ StreamID: f.StreamID,
+ Offset: int64(f.Offset),
+ Length: int64(f.DataLen()),
+ Fin: f.Fin,
+ },
}
case *wire.DatagramFrame:
- return &logging.DatagramFrame{
- Length: logging.ByteCount(len(f.Data)),
+ return qlog.Frame{
+ Frame: &qlog.DatagramFrame{
+ Length: int64(len(f.Data)),
+ },
}
default:
- return logging.Frame(frame)
+ return qlog.Frame{Frame: frame}
}
}
-func toLoggingAckFrame(f *wire.AckFrame) *logging.AckFrame {
- ack := &logging.AckFrame{
+func toQlogAckFrame(f *wire.AckFrame) *qlog.AckFrame {
+ ack := &qlog.AckFrame{
AckRanges: slices.Clone(f.AckRanges),
DelayTime: f.DelayTime,
ECNCE: f.ECNCE,
@@ -50,7 +57,7 @@ func toLoggingAckFrame(f *wire.AckFrame) *logging.AckFrame {
return ack
}
-func (c *Conn) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN) {
+func (c *Conn) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN, datagramID qlog.DatagramID) {
// quic-go logging
if c.logger.Debug() {
p.header.Log(c.logger)
@@ -66,90 +73,113 @@ func (c *Conn) logLongHeaderPacket(p *longHeaderPacket, ecn protocol.ECN) {
}
// tracing
- if c.tracer != nil && c.tracer.SentLongHeaderPacket != nil {
- frames := make([]logging.Frame, 0, len(p.frames))
+ if c.qlogger != nil {
+ numFrames := len(p.frames) + len(p.streamFrames)
+ if p.ack != nil {
+ numFrames++
+ }
+ frames := make([]qlog.Frame, 0, numFrames)
+ if p.ack != nil {
+ frames = append(frames, toQlogFrame(p.ack))
+ }
for _, f := range p.frames {
- frames = append(frames, toLoggingFrame(f.Frame))
+ frames = append(frames, toQlogFrame(f.Frame))
}
for _, f := range p.streamFrames {
- frames = append(frames, toLoggingFrame(f.Frame))
- }
- var ack *logging.AckFrame
- if p.ack != nil {
- ack = toLoggingAckFrame(p.ack)
+ frames = append(frames, toQlogFrame(f.Frame))
}
- c.tracer.SentLongHeaderPacket(p.header, p.length, ecn, ack, frames)
+ c.qlogger.RecordEvent(qlog.PacketSent{
+ Header: qlog.PacketHeader{
+ PacketType: toQlogPacketType(p.header.Type),
+ KeyPhaseBit: p.header.KeyPhase,
+ PacketNumber: p.header.PacketNumber,
+ Version: p.header.Version,
+ SrcConnectionID: p.header.SrcConnectionID,
+ DestConnectionID: p.header.DestConnectionID,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(p.length),
+ PayloadLength: int(p.header.Length),
+ },
+ DatagramID: datagramID,
+ Frames: frames,
+ ECN: toQlogECN(ecn),
+ })
}
}
-func (c *Conn) logShortHeaderPacket(
- destConnID protocol.ConnectionID,
- ackFrame *wire.AckFrame,
- frames []ackhandler.Frame,
- streamFrames []ackhandler.StreamFrame,
- pn protocol.PacketNumber,
- pnLen protocol.PacketNumberLen,
- kp protocol.KeyPhaseBit,
- ecn protocol.ECN,
- size protocol.ByteCount,
- isCoalesced bool,
-) {
+func (c *Conn) logShortHeaderPacket(p shortHeaderPacket, ecn protocol.ECN, size protocol.ByteCount) {
+ c.logShortHeaderPacketWithDatagramID(p, ecn, size, false, 0)
+}
+
+func (c *Conn) logShortHeaderPacketWithDatagramID(p shortHeaderPacket, ecn protocol.ECN, size protocol.ByteCount, isCoalesced bool, datagramID qlog.DatagramID) {
if c.logger.Debug() && !isCoalesced {
- c.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, 1-RTT (ECN: %s)", pn, size, c.logID, ecn)
+ c.logger.Debugf("-> Sending packet %d (%d bytes) for connection %s, 1-RTT (ECN: %s)", p.PacketNumber, size, c.logID, ecn)
}
// quic-go logging
if c.logger.Debug() {
- wire.LogShortHeader(c.logger, destConnID, pn, pnLen, kp)
- if ackFrame != nil {
- wire.LogFrame(c.logger, ackFrame, true)
+ wire.LogShortHeader(c.logger, p.DestConnID, p.PacketNumber, p.PacketNumberLen, p.KeyPhase)
+ if p.Ack != nil {
+ wire.LogFrame(c.logger, p.Ack, true)
}
- for _, f := range frames {
+ for _, f := range p.Frames {
wire.LogFrame(c.logger, f.Frame, true)
}
- for _, f := range streamFrames {
+ for _, f := range p.StreamFrames {
wire.LogFrame(c.logger, f.Frame, true)
}
}
// tracing
- if c.tracer != nil && c.tracer.SentShortHeaderPacket != nil {
- fs := make([]logging.Frame, 0, len(frames)+len(streamFrames))
- for _, f := range frames {
- fs = append(fs, toLoggingFrame(f.Frame))
- }
- for _, f := range streamFrames {
- fs = append(fs, toLoggingFrame(f.Frame))
- }
- var ack *logging.AckFrame
- if ackFrame != nil {
- ack = toLoggingAckFrame(ackFrame)
- }
- c.tracer.SentShortHeaderPacket(
- &logging.ShortHeader{DestConnectionID: destConnID, PacketNumber: pn, PacketNumberLen: pnLen, KeyPhase: kp},
- size,
- ecn,
- ack,
- fs,
- )
+ if c.qlogger != nil {
+ numFrames := len(p.Frames) + len(p.StreamFrames)
+ if p.Ack != nil {
+ numFrames++
+ }
+ fs := make([]qlog.Frame, 0, numFrames)
+ if p.Ack != nil {
+ fs = append(fs, toQlogFrame(p.Ack))
+ }
+ for _, f := range p.Frames {
+ fs = append(fs, toQlogFrame(f.Frame))
+ }
+ for _, f := range p.StreamFrames {
+ fs = append(fs, toQlogFrame(f.Frame))
+ }
+ c.qlogger.RecordEvent(qlog.PacketSent{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.PacketType1RTT,
+ KeyPhaseBit: p.KeyPhase,
+ PacketNumber: p.PacketNumber,
+ Version: c.version,
+ DestConnectionID: p.DestConnID,
+ },
+ Raw: qlog.RawInfo{
+ Length: int(size),
+ PayloadLength: int(size - wire.ShortHeaderLen(p.DestConnID, p.PacketNumberLen)),
+ },
+ DatagramID: datagramID,
+ Frames: fs,
+ ECN: toQlogECN(ecn),
+ })
}
}
func (c *Conn) logCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN) {
+ var datagramID qlog.DatagramID
+ if c.qlogger != nil {
+ datagramID = qlog.CalculateDatagramID(packet.buffer.Data)
+ }
if c.logger.Debug() {
// There's a short period between dropping both Initial and Handshake keys and completion of the handshake,
// during which we might call PackCoalescedPacket but just pack a short header packet.
if len(packet.longHdrPackets) == 0 && packet.shortHdrPacket != nil {
- c.logShortHeaderPacket(
- packet.shortHdrPacket.DestConnID,
- packet.shortHdrPacket.Ack,
- packet.shortHdrPacket.Frames,
- packet.shortHdrPacket.StreamFrames,
- packet.shortHdrPacket.PacketNumber,
- packet.shortHdrPacket.PacketNumberLen,
- packet.shortHdrPacket.KeyPhase,
+ c.logShortHeaderPacketWithDatagramID(
+ *packet.shortHdrPacket,
ecn,
packet.shortHdrPacket.Length,
false,
+ datagramID,
)
return
}
@@ -160,9 +190,126 @@ func (c *Conn) logCoalescedPacket(packet *coalescedPacket, ecn protocol.ECN) {
}
}
for _, p := range packet.longHdrPackets {
- c.logLongHeaderPacket(p, ecn)
+ c.logLongHeaderPacket(p, ecn, datagramID)
}
if p := packet.shortHdrPacket; p != nil {
- c.logShortHeaderPacket(p.DestConnID, p.Ack, p.Frames, p.StreamFrames, p.PacketNumber, p.PacketNumberLen, p.KeyPhase, ecn, p.Length, true)
+ c.logShortHeaderPacketWithDatagramID(*p, ecn, p.Length, true, datagramID)
+ }
+}
+
+func (c *Conn) qlogTransportParameters(tp *wire.TransportParameters, sentBy protocol.Perspective, restore bool) {
+ ev := qlog.ParametersSet{
+ Restore: restore,
+ OriginalDestinationConnectionID: tp.OriginalDestinationConnectionID,
+ InitialSourceConnectionID: tp.InitialSourceConnectionID,
+ RetrySourceConnectionID: tp.RetrySourceConnectionID,
+ StatelessResetToken: tp.StatelessResetToken,
+ DisableActiveMigration: tp.DisableActiveMigration,
+ MaxIdleTimeout: tp.MaxIdleTimeout,
+ MaxUDPPayloadSize: tp.MaxUDPPayloadSize,
+ AckDelayExponent: tp.AckDelayExponent,
+ MaxAckDelay: tp.MaxAckDelay,
+ ActiveConnectionIDLimit: tp.ActiveConnectionIDLimit,
+ InitialMaxData: tp.InitialMaxData,
+ InitialMaxStreamDataBidiLocal: tp.InitialMaxStreamDataBidiLocal,
+ InitialMaxStreamDataBidiRemote: tp.InitialMaxStreamDataBidiRemote,
+ InitialMaxStreamDataUni: tp.InitialMaxStreamDataUni,
+ InitialMaxStreamsBidi: int64(tp.MaxBidiStreamNum),
+ InitialMaxStreamsUni: int64(tp.MaxUniStreamNum),
+ MaxDatagramFrameSize: tp.MaxDatagramFrameSize,
+ EnableResetStreamAt: tp.EnableResetStreamAt,
+ }
+ if sentBy == c.perspective {
+ ev.Initiator = qlog.InitiatorLocal
+ } else {
+ ev.Initiator = qlog.InitiatorRemote
+ }
+ if tp.PreferredAddress != nil {
+ ev.PreferredAddress = &qlog.PreferredAddress{
+ IPv4: tp.PreferredAddress.IPv4,
+ IPv6: tp.PreferredAddress.IPv6,
+ ConnectionID: tp.PreferredAddress.ConnectionID,
+ StatelessResetToken: tp.PreferredAddress.StatelessResetToken,
+ }
+ }
+ c.qlogger.RecordEvent(ev)
+}
+
+func toQlogECN(ecn protocol.ECN) qlog.ECN {
+ //nolint:exhaustive // only need to handle the 3 valid values
+ switch ecn {
+ case protocol.ECT0:
+ return qlog.ECT0
+ case protocol.ECT1:
+ return qlog.ECT1
+ case protocol.ECNCE:
+ return qlog.ECNCE
+ default:
+ return qlog.ECNUnsupported
+ }
+}
+
+func toQlogPacketType(pt protocol.PacketType) qlog.PacketType {
+ var qpt qlog.PacketType
+ switch pt {
+ case protocol.PacketTypeInitial:
+ qpt = qlog.PacketTypeInitial
+ case protocol.PacketTypeHandshake:
+ qpt = qlog.PacketTypeHandshake
+ case protocol.PacketType0RTT:
+ qpt = qlog.PacketType0RTT
+ case protocol.PacketTypeRetry:
+ qpt = qlog.PacketTypeRetry
+ }
+ return qpt
+}
+
+func toPathEndpointInfo(addr *net.UDPAddr) qlog.PathEndpointInfo {
+ if addr == nil {
+ return qlog.PathEndpointInfo{}
+ }
+
+ var info qlog.PathEndpointInfo
+ if addr.IP == nil || addr.IP.To4() != nil {
+ addrPort := netip.AddrPortFrom(netip.AddrFrom4([4]byte(addr.IP.To4())), uint16(addr.Port))
+ if addrPort.IsValid() {
+ info.IPv4 = addrPort
+ }
+ } else {
+ addrPort := netip.AddrPortFrom(netip.AddrFrom16([16]byte(addr.IP.To16())), uint16(addr.Port))
+ if addrPort.IsValid() {
+ info.IPv6 = addrPort
+ }
+ }
+ return info
+}
+
+// startedConnectionEvent builds a StartedConnection event using consistent logic
+// for both endpoints. If the local address is unspecified (e.g., dual-stack
+// listener), it selects the family based on the remote address and uses the
+// unspecified address of that family with the local port.
+func startedConnectionEvent(local, remote *net.UDPAddr) qlog.StartedConnection {
+ var localInfo, remoteInfo qlog.PathEndpointInfo
+ if remote != nil {
+ remoteInfo = toPathEndpointInfo(remote)
+ }
+ if local != nil {
+ if local.IP == nil || local.IP.IsUnspecified() {
+ // Choose local family based on the remote address family.
+ if remote != nil && remote.IP.To4() != nil {
+ ap := netip.AddrPortFrom(netip.AddrFrom4([4]byte{}), uint16(local.Port))
+ if ap.IsValid() {
+ localInfo.IPv4 = ap
+ }
+ } else if remote != nil && remote.IP.To16() != nil && remote.IP.To4() == nil {
+ ap := netip.AddrPortFrom(netip.AddrFrom16([16]byte{}), uint16(local.Port))
+ if ap.IsValid() {
+ localInfo.IPv6 = ap
+ }
+ }
+ } else {
+ localInfo = toPathEndpointInfo(local)
+ }
}
+ return qlog.StartedConnection{Local: localInfo, Remote: remoteInfo}
}
diff --git a/vendor/github.com/quic-go/quic-go/frame_sorter.go b/vendor/github.com/quic-go/quic-go/frame_sorter.go
index bee0abadb5..20c6d9cc08 100644
--- a/vendor/github.com/quic-go/quic-go/frame_sorter.go
+++ b/vendor/github.com/quic-go/quic-go/frame_sorter.go
@@ -235,3 +235,40 @@ func (s *frameSorter) Pop() (protocol.ByteCount, []byte, func()) {
func (s *frameSorter) HasMoreData() bool {
return len(s.queue) > 0
}
+
+var errTooLittleData = errors.New("too little data")
+
+// Peek copies len(p) consecutive bytes starting at offset into p, without removing them.
+// It is only possible to peek from an offset where a frame starts.
+//
+// If there isn't enough consecutive data available, errTooLittleData is returned.
+func (s *frameSorter) Peek(offset protocol.ByteCount, p []byte) error {
+ if len(p) == 0 {
+ return nil
+ }
+
+ // first, check if we have enough consecutive data available
+ pos := offset
+ remaining := len(p)
+ for remaining > 0 {
+ entry, ok := s.queue[pos]
+ if !ok {
+ return errTooLittleData
+ }
+ entryLen := len(entry.Data)
+ if remaining <= entryLen {
+ break // enough data available
+ }
+ remaining -= entryLen
+ pos += protocol.ByteCount(entryLen)
+ }
+
+ pos = offset
+ var copied int
+ for copied < len(p) {
+ entry := s.queue[pos] // the entry is guaranteed to exist from the check above
+ copied += copy(p[copied:], entry.Data)
+ pos += protocol.ByteCount(len(entry.Data))
+ }
+ return nil
+}
diff --git a/vendor/github.com/quic-go/quic-go/interface.go b/vendor/github.com/quic-go/quic-go/interface.go
index 45a03a52ac..119e320560 100644
--- a/vendor/github.com/quic-go/quic-go/interface.go
+++ b/vendor/github.com/quic-go/quic-go/interface.go
@@ -10,7 +10,7 @@ import (
"github.com/quic-go/quic-go/internal/handshake"
"github.com/quic-go/quic-go/internal/protocol"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlogwriter"
)
// The StreamID is the ID of a QUIC stream.
@@ -58,20 +58,6 @@ type TokenStore interface {
// when the server rejects a 0-RTT connection attempt.
var Err0RTTRejected = errors.New("0-RTT rejected")
-// ConnectionTracingKey can be used to associate a [logging.ConnectionTracer] with a [Conn].
-// It is set on the Conn.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.ClientInfo.Context.
var QUICVersionContextKey = handshake.QUICVersionContextKey
@@ -189,13 +175,9 @@ type Config struct {
// Enable QUIC Stream Resets with Partial Delivery.
// See https://datatracker.ietf.org/doc/html/draft-ietf-quic-reliable-stream-reset-07.
EnableStreamResetPartialDelivery bool
- Tracer func(context.Context, logging.Perspective, ConnectionID) *logging.ConnectionTracer
-}
-// ClientHelloInfo contains information about an incoming connection attempt.
-//
-// Deprecated: Use ClientInfo instead.
-type ClientHelloInfo = ClientInfo
+ Tracer func(ctx context.Context, isClient bool, connID ConnectionID) qlogwriter.Trace
+}
// ClientInfo contains information about an incoming connection attempt.
type ClientInfo struct {
@@ -212,13 +194,18 @@ type ClientInfo struct {
type ConnectionState struct {
// TLS contains information about the TLS connection state, incl. the tls.ConnectionState.
TLS tls.ConnectionState
- // SupportsDatagrams indicates whether the peer advertised support for QUIC datagrams (RFC 9221).
- // When true, datagrams can be sent using the Conn's SendDatagram method.
- // This is a unilateral declaration by the peer - receiving datagrams is only possible if
- // datagram support was enabled locally via Config.EnableDatagrams.
- SupportsDatagrams bool
- // SupportsStreamResetPartialDelivery indicates whether the peer advertised support for QUIC Stream Resets with Partial Delivery.
- SupportsStreamResetPartialDelivery bool
+ // SupportsDatagrams indicates support for QUIC datagrams (RFC 9221).
+ SupportsDatagrams struct {
+ // Remote is true if the peer advertised datagram support.
+ // Local is true if datagram support was enabled via Config.EnableDatagrams.
+ Remote, Local bool
+ }
+ // SupportsStreamResetPartialDelivery indicates support for QUIC Stream Resets with Partial Delivery.
+ SupportsStreamResetPartialDelivery struct {
+ // Remote is true if the peer advertised support.
+ // Local is true if support was enabled via Config.EnableStreamResetPartialDelivery.
+ Remote, Local bool
+ }
// Used0RTT says if 0-RTT resumption was used.
Used0RTT bool
// Version is the QUIC version of the QUIC connection.
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go
deleted file mode 100644
index f1bac32763..0000000000
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/ackhandler.go
+++ /dev/null
@@ -1,25 +0,0 @@
-package ackhandler
-
-import (
- "github.com/quic-go/quic-go/internal/protocol"
- "github.com/quic-go/quic-go/internal/utils"
- "github.com/quic-go/quic-go/logging"
-)
-
-// NewAckHandler creates a new SentPacketHandler and a new ReceivedPacketHandler.
-// clientAddressValidated indicates whether the address was validated beforehand by an address validation token.
-// clientAddressValidated has no effect for a client.
-func NewAckHandler(
- initialPacketNumber protocol.PacketNumber,
- initialMaxDatagramSize protocol.ByteCount,
- rttStats *utils.RTTStats,
- connStats *utils.ConnectionStats,
- clientAddressValidated bool,
- enableECN bool,
- pers protocol.Perspective,
- tracer *logging.ConnectionTracer,
- logger utils.Logger,
-) (SentPacketHandler, ReceivedPacketHandler) {
- sph := newSentPacketHandler(initialPacketNumber, initialMaxDatagramSize, rttStats, connStats, clientAddressValidated, enableECN, pers, tracer, logger)
- return sph, newReceivedPacketHandler(sph, logger)
-}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
index 1b462a6065..123d3a341d 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/ecn.go
@@ -5,7 +5,8 @@ import (
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
)
type ecnState uint8
@@ -18,6 +19,22 @@ const (
ecnStateFailed
)
+const (
+ // ecnFailedNoECNCounts is emitted when an ACK acknowledges ECN-marked packets,
+ // but doesn't contain any ECN counts
+ ecnFailedNoECNCounts = "ACK doesn't contain ECN marks"
+ // ecnFailedDecreasedECNCounts is emitted when an ACK frame decreases ECN counts
+ ecnFailedDecreasedECNCounts = "ACK decreases ECN counts"
+ // ecnFailedLostAllTestingPackets is emitted when all ECN testing packets are declared lost
+ ecnFailedLostAllTestingPackets = "all ECN testing packets declared lost"
+ // ecnFailedMoreECNCountsThanSent is emitted when an ACK contains more ECN counts than ECN-marked packets were sent
+ ecnFailedMoreECNCountsThanSent = "ACK contains more ECN counts than ECN-marked packets sent"
+ // ecnFailedTooFewECNCounts is emitted when an ACK contains fewer ECN counts than it acknowledges packets
+ ecnFailedTooFewECNCounts = "ACK contains fewer new ECN counts than acknowledged ECN-marked packets"
+ // ecnFailedManglingDetected is emitted when the path marks all ECN-marked packets as CE
+ ecnFailedManglingDetected = "ECN mangling detected"
+)
+
// must fit into an uint8, otherwise numSentTesting and numLostTesting must have a larger type
const numECNTestingPackets = 10
@@ -45,20 +62,20 @@ type ecnTracker struct {
numSentECT0, numSentECT1 int64
numAckedECT0, numAckedECT1, numAckedECNCE int64
- tracer *logging.ConnectionTracer
- logger utils.Logger
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
}
var _ ecnHandler = &ecnTracker{}
-func newECNTracker(logger utils.Logger, tracer *logging.ConnectionTracer) *ecnTracker {
+func newECNTracker(logger utils.Logger, qlogger qlogwriter.Recorder) *ecnTracker {
return &ecnTracker{
firstTestingPacket: protocol.InvalidPacketNumber,
lastTestingPacket: protocol.InvalidPacketNumber,
firstCapablePacket: protocol.InvalidPacketNumber,
state: ecnStateInitial,
logger: logger,
- tracer: tracer,
+ qlogger: qlogger,
}
}
@@ -92,8 +109,10 @@ func (e *ecnTracker) SentPacket(pn protocol.PacketNumber, ecn protocol.ECN) {
e.firstTestingPacket = pn
}
if e.numSentECT0+e.numSentECT1 >= numECNTestingPackets {
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateUnknown, logging.ECNTriggerNoTrigger)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateUnknown,
+ })
}
e.state = ecnStateUnknown
e.lastTestingPacket = pn
@@ -103,8 +122,10 @@ func (e *ecnTracker) SentPacket(pn protocol.PacketNumber, ecn protocol.ECN) {
func (e *ecnTracker) Mode() protocol.ECN {
switch e.state {
case ecnStateInitial:
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateTesting, logging.ECNTriggerNoTrigger)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateTesting,
+ })
}
e.state = ecnStateTesting
return e.Mode()
@@ -131,8 +152,11 @@ func (e *ecnTracker) LostPacket(pn protocol.PacketNumber) {
}
if e.numLostTesting >= e.numSentTesting {
e.logger.Debugf("Disabling ECN. All testing packets were lost.")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedLostAllTestingPackets)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedLostAllTestingPackets,
+ })
}
e.state = ecnStateFailed
return
@@ -153,8 +177,11 @@ func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ec
// the total number of packets sent with each corresponding ECT codepoint.
if ect0 > e.numSentECT0 || ect1 > e.numSentECT1 {
e.logger.Debugf("Disabling ECN. Received more ECT(0) / ECT(1) acknowledgements than packets sent.")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedMoreECNCountsThanSent)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedMoreECNCountsThanSent,
+ })
}
e.state = ecnStateFailed
return false
@@ -179,8 +206,11 @@ func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ec
// * peers that don't report any ECN counts
if (ackedECT0 > 0 || ackedECT1 > 0) && ect0 == 0 && ect1 == 0 && ecnce == 0 {
e.logger.Debugf("Disabling ECN. ECN-marked packet acknowledged, but no ECN counts on ACK frame.")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedNoECNCounts)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedNoECNCounts,
+ })
}
e.state = ecnStateFailed
return false
@@ -196,8 +226,11 @@ func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ec
// Any decrease means that the peer's counting logic is broken.
if newECT0 < 0 || newECT1 < 0 || newECNCE < 0 {
e.logger.Debugf("Disabling ECN. ECN counts decreased unexpectedly.")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedDecreasedECNCounts)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedDecreasedECNCounts,
+ })
}
e.state = ecnStateFailed
return false
@@ -208,8 +241,11 @@ func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ec
// This could be the result of (partial) bleaching.
if newECT0+newECNCE < ackedECT0 {
e.logger.Debugf("Disabling ECN. Received less ECT(0) + ECN-CE than packets sent with ECT(0).")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedTooFewECNCounts)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedTooFewECNCounts,
+ })
}
e.state = ecnStateFailed
return false
@@ -218,8 +254,11 @@ func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ec
// the number of newly acknowledged packets sent with an ECT(1) marking.
if newECT1+newECNCE < ackedECT1 {
e.logger.Debugf("Disabling ECN. Received less ECT(1) + ECN-CE than packets sent with ECT(1).")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedTooFewECNCounts)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedTooFewECNCounts,
+ })
}
e.state = ecnStateFailed
return false
@@ -249,8 +288,10 @@ func (e *ecnTracker) HandleNewlyAcked(packets []packetWithPacketNumber, ect0, ec
// This check won't succeed if the path is mangling ECN-marks (i.e. rewrites all ECN-marked packets to CE).
if ackedTestingPacket && (newECT0 > 0 || newECT1 > 0) {
e.logger.Debugf("ECN capability confirmed.")
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateCapable, logging.ECNTriggerNoTrigger)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateCapable,
+ })
}
e.state = ecnStateCapable
}
@@ -267,8 +308,11 @@ func (e *ecnTracker) failIfMangled() {
if e.numSentECT0+e.numSentECT1 > numAckedECNCE {
return
}
- if e.tracer != nil && e.tracer.ECNStateUpdated != nil {
- e.tracer.ECNStateUpdated(logging.ECNStateFailed, logging.ECNFailedManglingDetected)
+ if e.qlogger != nil {
+ e.qlogger.RecordEvent(qlog.ECNStateUpdated{
+ State: qlog.ECNStateFailed,
+ Trigger: ecnFailedManglingDetected,
+ })
}
e.state = ecnStateFailed
}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
index 9ee9da7d99..620a5e11f0 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/interfaces.go
@@ -13,6 +13,7 @@ type SentPacketHandler interface {
// ReceivedAck processes an ACK frame.
// It does not store a copy of the frame.
ReceivedAck(f *wire.AckFrame, encLevel protocol.EncryptionLevel, rcvTime monotime.Time) (bool /* 1-RTT packet acked */, error)
+ ReceivedPacket(protocol.EncryptionLevel, monotime.Time)
ReceivedBytes(_ protocol.ByteCount, rcvTime monotime.Time)
DropPackets(_ protocol.EncryptionLevel, rcvTime monotime.Time)
ResetForRetry(rcvTime monotime.Time)
@@ -36,18 +37,3 @@ type SentPacketHandler interface {
MigratedPath(now monotime.Time, initialMaxPacketSize protocol.ByteCount)
}
-
-type sentPacketTracker interface {
- GetLowestPacketNotConfirmedAcked() protocol.PacketNumber
- ReceivedPacket(_ protocol.EncryptionLevel, rcvTime monotime.Time)
-}
-
-// ReceivedPacketHandler handles ACKs needed to send for incoming packets
-type ReceivedPacketHandler interface {
- IsPotentiallyDuplicate(protocol.PacketNumber, protocol.EncryptionLevel) bool
- ReceivedPacket(pn protocol.PacketNumber, ecn protocol.ECN, encLevel protocol.EncryptionLevel, rcvTime monotime.Time, ackEliciting bool) error
- DropPackets(protocol.EncryptionLevel)
-
- GetAlarmTimeout() monotime.Time
- GetAckFrame(_ protocol.EncryptionLevel, now monotime.Time, onlyIfQueued bool) *wire.AckFrame
-}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
index 323d9fde9f..3add80d1f3 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/mockgen.go
@@ -2,8 +2,5 @@
package ackhandler
-//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_sent_packet_tracker_test.go github.com/quic-go/quic-go/internal/ackhandler SentPacketTracker"
-type SentPacketTracker = sentPacketTracker
-
//go:generate sh -c "go tool mockgen -typed -build_flags=\"-tags=gomock\" -package ackhandler -destination mock_ecn_handler_test.go github.com/quic-go/quic-go/internal/ackhandler ECNHandler"
type ECNHandler = ecnHandler
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
index f0500e9f2d..7d9863000a 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/packet.go
@@ -24,12 +24,15 @@ type packet struct {
IsPathMTUProbePacket bool // We don't report the loss of Path MTU probe packets to the congestion controller.
includedInBytesInFlight bool
- declaredLost bool
isPathProbePacket bool
}
-func (p *packet) outstanding() bool {
- return !p.declaredLost && !p.IsPathMTUProbePacket && !p.isPathProbePacket
+func (p *packet) Outstanding() bool {
+ return !p.IsPathMTUProbePacket && !p.isPathProbePacket && p.IsAckEliciting()
+}
+
+func (p *packet) IsAckEliciting() bool {
+ return len(p.StreamFrames) > 0 || len(p.Frames) > 0
}
var packetPool = sync.Pool{New: func() any { return &packet{} }}
@@ -44,7 +47,6 @@ func getPacket() *packet {
p.SendTime = 0
p.IsPathMTUProbePacket = false
p.includedInBytesInFlight = false
- p.declaredLost = false
p.isPathProbePacket = false
return p
}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
index 7180db85f1..d0d24bf30a 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_handler.go
@@ -9,9 +9,7 @@ import (
"github.com/quic-go/quic-go/internal/wire"
)
-type receivedPacketHandler struct {
- sentPackets sentPacketTracker
-
+type ReceivedPacketHandler struct {
initialPackets *receivedPacketTracker
handshakePackets *receivedPacketTracker
appDataPackets appDataReceivedPacketTracker
@@ -19,11 +17,8 @@ type receivedPacketHandler struct {
lowest1RTTPacket protocol.PacketNumber
}
-var _ ReceivedPacketHandler = &receivedPacketHandler{}
-
-func newReceivedPacketHandler(sentPackets sentPacketTracker, logger utils.Logger) ReceivedPacketHandler {
- return &receivedPacketHandler{
- sentPackets: sentPackets,
+func NewReceivedPacketHandler(logger utils.Logger) *ReceivedPacketHandler {
+ return &ReceivedPacketHandler{
initialPackets: newReceivedPacketTracker(),
handshakePackets: newReceivedPacketTracker(),
appDataPackets: *newAppDataReceivedPacketTracker(logger),
@@ -31,14 +26,13 @@ func newReceivedPacketHandler(sentPackets sentPacketTracker, logger utils.Logger
}
}
-func (h *receivedPacketHandler) ReceivedPacket(
+func (h *ReceivedPacketHandler) ReceivedPacket(
pn protocol.PacketNumber,
ecn protocol.ECN,
encLevel protocol.EncryptionLevel,
rcvTime monotime.Time,
ackEliciting bool,
) error {
- h.sentPackets.ReceivedPacket(encLevel, rcvTime)
switch encLevel {
case protocol.EncryptionInitial:
return h.initialPackets.ReceivedPacket(pn, ecn, ackEliciting)
@@ -58,17 +52,17 @@ func (h *receivedPacketHandler) ReceivedPacket(
if h.lowest1RTTPacket == protocol.InvalidPacketNumber || pn < h.lowest1RTTPacket {
h.lowest1RTTPacket = pn
}
- if err := h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting); err != nil {
- return err
- }
- h.appDataPackets.IgnoreBelow(h.sentPackets.GetLowestPacketNotConfirmedAcked())
- return nil
+ return h.appDataPackets.ReceivedPacket(pn, ecn, rcvTime, ackEliciting)
default:
panic(fmt.Sprintf("received packet with unknown encryption level: %s", encLevel))
}
}
-func (h *receivedPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
+func (h *ReceivedPacketHandler) IgnorePacketsBelow(pn protocol.PacketNumber) {
+ h.appDataPackets.IgnoreBelow(pn)
+}
+
+func (h *ReceivedPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
//nolint:exhaustive // 1-RTT packet number space is never dropped.
switch encLevel {
case protocol.EncryptionInitial:
@@ -83,11 +77,11 @@ func (h *receivedPacketHandler) DropPackets(encLevel protocol.EncryptionLevel) {
}
}
-func (h *receivedPacketHandler) GetAlarmTimeout() monotime.Time {
+func (h *ReceivedPacketHandler) GetAlarmTimeout() monotime.Time {
return h.appDataPackets.GetAlarmTimeout()
}
-func (h *receivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel, now monotime.Time, onlyIfQueued bool) *wire.AckFrame {
+func (h *ReceivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel, now monotime.Time, onlyIfQueued bool) *wire.AckFrame {
//nolint:exhaustive // 0-RTT packets can't contain ACK frames.
switch encLevel {
case protocol.EncryptionInitial:
@@ -108,7 +102,7 @@ func (h *receivedPacketHandler) GetAckFrame(encLevel protocol.EncryptionLevel, n
}
}
-func (h *receivedPacketHandler) IsPotentiallyDuplicate(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) bool {
+func (h *ReceivedPacketHandler) IsPotentiallyDuplicate(pn protocol.PacketNumber, encLevel protocol.EncryptionLevel) bool {
switch encLevel {
case protocol.EncryptionInitial:
if h.initialPackets != nil {
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
index 80f154ba86..64092cccf8 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/received_packet_tracker.go
@@ -155,6 +155,9 @@ func (h *appDataReceivedPacketTracker) isMissing(p protocol.PacketNumber) bool {
}
func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
+ if h.lastAck == nil {
+ return false
+ }
if h.largestObserved < reorderingThreshold {
return false
}
@@ -170,12 +173,6 @@ func (h *appDataReceivedPacketTracker) hasNewMissingPackets() bool {
}
func (h *appDataReceivedPacketTracker) shouldQueueACK(pn protocol.PacketNumber, ecn protocol.ECN, wasMissing bool) bool {
- // always acknowledge the first packet
- if h.lastAck == nil {
- h.logger.Debugf("\tQueueing ACK because the first packet should be acknowledged.")
- return true
- }
-
// Send an ACK if this packet was reported missing in an ACK sent before.
// Ack decimation with reordering relies on the timer to send an ACK, but if
// missing packets we reported in the previous ACK, send an ACK immediately.
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 11739e2258..9b539eadd0 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
@@ -11,7 +11,8 @@ import (
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/internal/wire"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
)
const (
@@ -59,7 +60,7 @@ func newPacketNumberSpace(initialPN protocol.PacketNumber, isAppData bool) *pack
type alarmTimer struct {
Time monotime.Time
- TimerType logging.TimerType
+ TimerType qlog.TimerType
EncryptionLevel protocol.EncryptionLevel
}
@@ -68,6 +69,8 @@ type sentPacketHandler struct {
handshakePackets *packetNumberSpace
appDataPackets *packetNumberSpace
lostPackets lostPacketTracker // only for application-data packet number space
+ // send time of the largest acknowledged packet, across all packet number spaces
+ largestAckedTime monotime.Time
// Do we know that the peer completed address validation yet?
// Always true for the server.
@@ -80,11 +83,7 @@ type sentPacketHandler struct {
handshakeConfirmed bool
- // lowestNotConfirmedAcked is the lowest packet number that we sent an ACK for, but haven't received confirmation, that this ACK actually arrived
- // example: we send an ACK for packets 90-100 with packet number 20
- // once we receive an ACK from the peer for packet 20, the lowestNotConfirmedAcked is 101
- // Only applies to the application-data packet number space.
- lowestNotConfirmedAcked protocol.PacketNumber
+ ignorePacketsBelow func(protocol.PacketNumber)
ackedPackets []packetWithPacketNumber // to avoid allocations in detectAndRemoveAckedPackets
@@ -109,35 +108,34 @@ type sentPacketHandler struct {
perspective protocol.Perspective
- tracer *logging.ConnectionTracer
- logger utils.Logger
+ qlogger qlogwriter.Recorder
+ lastMetrics qlog.MetricsUpdated
+ logger utils.Logger
}
-var (
- _ SentPacketHandler = &sentPacketHandler{}
- _ sentPacketTracker = &sentPacketHandler{}
-)
+var _ SentPacketHandler = &sentPacketHandler{}
// clientAddressValidated indicates whether the address was validated beforehand by an address validation token.
// If the address was validated, the amplification limit doesn't apply. It has no effect for a client.
-func newSentPacketHandler(
+func NewSentPacketHandler(
initialPN protocol.PacketNumber,
initialMaxDatagramSize protocol.ByteCount,
rttStats *utils.RTTStats,
connStats *utils.ConnectionStats,
clientAddressValidated bool,
enableECN bool,
+ ignorePacketsBelow func(protocol.PacketNumber),
pers protocol.Perspective,
- tracer *logging.ConnectionTracer,
+ qlogger qlogwriter.Recorder,
logger utils.Logger,
-) *sentPacketHandler {
+) SentPacketHandler {
congestion := congestion.NewCubicSender(
congestion.DefaultClock{},
rttStats,
connStats,
initialMaxDatagramSize,
true, // use Reno
- tracer,
+ qlogger,
)
h := &sentPacketHandler{
@@ -150,13 +148,14 @@ func newSentPacketHandler(
rttStats: rttStats,
connStats: connStats,
congestion: congestion,
+ ignorePacketsBelow: ignorePacketsBelow,
perspective: pers,
- tracer: tracer,
+ qlogger: qlogger,
logger: logger,
}
if enableECN {
h.enableECN = true
- h.ecnTracker = newECNTracker(logger, tracer)
+ h.ecnTracker = newECNTracker(logger, qlogger)
}
return h
}
@@ -213,8 +212,8 @@ func (h *sentPacketHandler) DropPackets(encLevel protocol.EncryptionLevel, now m
default:
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
}
- if h.tracer != nil && h.tracer.UpdatedPTOCount != nil && h.ptoCount != 0 {
- h.tracer.UpdatedPTOCount(0)
+ if h.qlogger != nil && h.ptoCount != 0 {
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
}
h.ptoCount = 0
h.numProbesToSend = 0
@@ -240,12 +239,12 @@ func (h *sentPacketHandler) ReceivedPacket(l protocol.EncryptionLevel, t monotim
}
func (h *sentPacketHandler) packetsInFlight() int {
- packetsInFlight := h.appDataPackets.history.Len()
+ packetsInFlight := h.appDataPackets.history.NumOutstanding()
if h.handshakePackets != nil {
- packetsInFlight += h.handshakePackets.history.Len()
+ packetsInFlight += h.handshakePackets.history.NumOutstanding()
}
if h.initialPackets != nil {
- packetsInFlight += h.initialPackets.history.Len()
+ packetsInFlight += h.initialPackets.history.NumOutstanding()
}
return packetsInFlight
}
@@ -273,15 +272,19 @@ func (h *sentPacketHandler) SentPacket(
}
pnSpace.largestSent = pn
- isAckEliciting := len(streamFrames) > 0 || len(frames) > 0
+
+ p := getPacket()
+ p.SendTime = t
+ p.EncryptionLevel = encLevel
+ p.Length = size
+ p.Frames = frames
+ p.LargestAcked = largestAcked
+ p.StreamFrames = streamFrames
+ p.IsPathMTUProbePacket = isPathMTUProbePacket
+ p.isPathProbePacket = isPathProbePacket
+ isAckEliciting := p.IsAckEliciting()
if isPathProbePacket {
- p := getPacket()
- p.SendTime = t
- p.EncryptionLevel = encLevel
- p.Length = size
- p.Frames = frames
- p.isPathProbePacket = true
pnSpace.history.SentPathProbePacket(pn, p)
h.setLossDetectionTimer(t)
return
@@ -289,6 +292,7 @@ func (h *sentPacketHandler) SentPacket(
if isAckEliciting {
pnSpace.lastAckElicitingPacketTime = t
h.bytesInFlight += size
+ p.includedInBytesInFlight = true
if h.numProbesToSend > 0 {
h.numProbesToSend--
}
@@ -299,31 +303,65 @@ func (h *sentPacketHandler) SentPacket(
h.ecnTracker.SentPacket(pn, ecn)
}
+ pnSpace.history.SentPacket(pn, p)
if !isAckEliciting {
- pnSpace.history.SentNonAckElicitingPacket(pn)
if !h.peerCompletedAddressValidation {
h.setLossDetectionTimer(t)
}
return
}
-
- p := getPacket()
- p.SendTime = t
- p.EncryptionLevel = encLevel
- p.Length = size
- p.LargestAcked = largestAcked
- p.StreamFrames = streamFrames
- p.Frames = frames
- p.IsPathMTUProbePacket = isPathMTUProbePacket
- p.includedInBytesInFlight = true
-
- pnSpace.history.SentAckElicitingPacket(pn, p)
- if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
- h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
+ if h.qlogger != nil {
+ h.qlogMetricsUpdated()
}
h.setLossDetectionTimer(t)
}
+func (h *sentPacketHandler) qlogMetricsUpdated() {
+ var metricsUpdatedEvent qlog.MetricsUpdated
+ var updated bool
+ if h.rttStats.HasMeasurement() {
+ if h.lastMetrics.MinRTT != h.rttStats.MinRTT() {
+ metricsUpdatedEvent.MinRTT = h.rttStats.MinRTT()
+ h.lastMetrics.MinRTT = metricsUpdatedEvent.MinRTT
+ updated = true
+ }
+ if h.lastMetrics.SmoothedRTT != h.rttStats.SmoothedRTT() {
+ metricsUpdatedEvent.SmoothedRTT = h.rttStats.SmoothedRTT()
+ h.lastMetrics.SmoothedRTT = metricsUpdatedEvent.SmoothedRTT
+ updated = true
+ }
+ if h.lastMetrics.LatestRTT != h.rttStats.LatestRTT() {
+ metricsUpdatedEvent.LatestRTT = h.rttStats.LatestRTT()
+ h.lastMetrics.LatestRTT = metricsUpdatedEvent.LatestRTT
+ updated = true
+ }
+ if h.lastMetrics.RTTVariance != h.rttStats.MeanDeviation() {
+ metricsUpdatedEvent.RTTVariance = h.rttStats.MeanDeviation()
+ h.lastMetrics.RTTVariance = metricsUpdatedEvent.RTTVariance
+ updated = true
+ }
+ }
+ if cwnd := h.congestion.GetCongestionWindow(); h.lastMetrics.CongestionWindow != int(cwnd) {
+ metricsUpdatedEvent.CongestionWindow = int(cwnd)
+ h.lastMetrics.CongestionWindow = metricsUpdatedEvent.CongestionWindow
+ updated = true
+ }
+ if h.lastMetrics.BytesInFlight != int(h.bytesInFlight) {
+ metricsUpdatedEvent.BytesInFlight = int(h.bytesInFlight)
+ h.lastMetrics.BytesInFlight = metricsUpdatedEvent.BytesInFlight
+ updated = true
+ }
+ packetsInFlight := h.packetsInFlight()
+ if h.lastMetrics.PacketsInFlight != packetsInFlight {
+ metricsUpdatedEvent.PacketsInFlight = packetsInFlight
+ h.lastMetrics.PacketsInFlight = metricsUpdatedEvent.PacketsInFlight
+ updated = true
+ }
+ if updated {
+ h.qlogger.RecordEvent(metricsUpdatedEvent)
+ }
+}
+
func (h *sentPacketHandler) getPacketNumberSpace(encLevel protocol.EncryptionLevel) *packetNumberSpace {
switch encLevel {
case protocol.EncryptionInitial:
@@ -358,21 +396,26 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
}
priorInFlight := h.bytesInFlight
- ackedPackets, err := h.detectAndRemoveAckedPackets(ack, encLevel)
+ ackedPackets, hasAckEliciting, err := h.detectAndRemoveAckedPackets(ack, encLevel)
if err != nil || len(ackedPackets) == 0 {
return false, err
}
- // update the RTT, if the largest acked is newly acknowledged
+ // update the RTT, if:
+ // * the largest acked is newly acknowledged, AND
+ // * at least one new ack-eliciting packet was acknowledged
if len(ackedPackets) > 0 {
- if p := ackedPackets[len(ackedPackets)-1]; p.PacketNumber == ack.LargestAcked() && !p.isPathProbePacket {
+ if p := ackedPackets[len(ackedPackets)-1]; p.PacketNumber == ack.LargestAcked() && !p.isPathProbePacket && hasAckEliciting {
// don't use the ack delay for Initial and Handshake packets
var ackDelay time.Duration
if encLevel == protocol.Encryption1RTT {
ackDelay = min(ack.DelayTime, h.rttStats.MaxAckDelay())
}
- h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackDelay)
- if h.logger.Debug() {
- h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
+ if h.largestAckedTime.IsZero() || !p.SendTime.Before(h.largestAckedTime) {
+ h.rttStats.UpdateRTT(rcvTime.Sub(p.SendTime), ackDelay)
+ if h.logger.Debug() {
+ h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
+ }
+ h.largestAckedTime = p.SendTime
}
h.congestion.MaybeExitSlowStart()
}
@@ -394,7 +437,7 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
}
var acked1RTTPacket bool
for _, p := range ackedPackets {
- if p.includedInBytesInFlight && !p.declaredLost {
+ if p.includedInBytesInFlight {
h.congestion.OnPacketAcked(p.PacketNumber, p.Length, priorInFlight, rcvTime)
}
if p.EncryptionLevel == protocol.Encryption1RTT {
@@ -424,15 +467,15 @@ func (h *sentPacketHandler) ReceivedAck(ack *wire.AckFrame, encLevel protocol.En
// Reset the pto_count unless the client is unsure if the server has validated the client's address.
if h.peerCompletedAddressValidation {
- if h.tracer != nil && h.tracer.UpdatedPTOCount != nil && h.ptoCount != 0 {
- h.tracer.UpdatedPTOCount(0)
+ if h.qlogger != nil && h.ptoCount != 0 {
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
}
h.ptoCount = 0
}
h.numProbesToSend = 0
- if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
- h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
+ if h.qlogger != nil {
+ h.qlogMetricsUpdated()
}
h.setLossDetectionTimer(rcvTime)
@@ -463,8 +506,13 @@ func (h *sentPacketHandler) detectSpuriousLosses(ack *wire.AckFrame, ackTime mon
maxPacketReordering = max(maxPacketReordering, packetReordering)
maxTimeReordering = max(maxTimeReordering, timeReordering)
- if h.tracer != nil && h.tracer.DetectedSpuriousLoss != nil {
- h.tracer.DetectedSpuriousLoss(protocol.Encryption1RTT, pn, uint64(packetReordering), timeReordering)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.SpuriousLoss{
+ EncryptionLevel: protocol.Encryption1RTT,
+ PacketNumber: pn,
+ PacketReordering: uint64(packetReordering),
+ TimeReordering: timeReordering,
+ })
}
spuriousLosses = append(spuriousLosses, pn)
}
@@ -474,14 +522,13 @@ func (h *sentPacketHandler) detectSpuriousLosses(ack *wire.AckFrame, ackTime mon
}
}
-func (h *sentPacketHandler) GetLowestPacketNotConfirmedAcked() protocol.PacketNumber {
- return h.lowestNotConfirmedAcked
-}
-
// Packets are returned in ascending packet number order.
-func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encLevel protocol.EncryptionLevel) ([]packetWithPacketNumber, error) {
+func (h *sentPacketHandler) detectAndRemoveAckedPackets(
+ ack *wire.AckFrame,
+ encLevel protocol.EncryptionLevel,
+) (_ []packetWithPacketNumber, hasAckEliciting bool, _ error) {
if len(h.ackedPackets) > 0 {
- return nil, errors.New("ackhandler BUG: ackedPackets slice not empty")
+ return nil, false, errors.New("ackhandler BUG: ackedPackets slice not empty")
}
pnSpace := h.getPacketNumberSpace(encLevel)
@@ -489,7 +536,7 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
if encLevel == protocol.Encryption1RTT {
for p := range pnSpace.history.SkippedPackets() {
if ack.AcksPacket(p) {
- return nil, &qerr.TransportError{
+ return nil, false, &qerr.TransportError{
ErrorCode: qerr.ProtocolViolation,
ErrorMessage: fmt.Sprintf("received an ACK for skipped packet number: %d (%s)", p, encLevel),
}
@@ -521,7 +568,7 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
continue
}
if pn > ackRange.Largest {
- return nil, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", pn, ackRange.Smallest, ackRange.Largest)
+ return nil, false, fmt.Errorf("BUG: ackhandler would have acked wrong packet %d, while evaluating range %d -> %d", pn, ackRange.Smallest, ackRange.Largest)
}
}
if p.isPathProbePacket {
@@ -532,6 +579,9 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
}
continue
}
+ if p.IsAckEliciting() {
+ hasAckEliciting = true
+ }
h.ackedPackets = append(h.ackedPackets, packetWithPacketNumber{PacketNumber: pn, packet: p})
}
if h.logger.Debug() && len(h.ackedPackets) > 0 {
@@ -543,8 +593,8 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
}
for _, p := range h.ackedPackets {
- if p.LargestAcked != protocol.InvalidPacketNumber && encLevel == protocol.Encryption1RTT {
- h.lowestNotConfirmedAcked = max(h.lowestNotConfirmedAcked, p.LargestAcked+1)
+ if p.LargestAcked != protocol.InvalidPacketNumber && encLevel == protocol.Encryption1RTT && h.ignorePacketsBelow != nil {
+ h.ignorePacketsBelow(p.LargestAcked + 1)
}
for _, f := range p.Frames {
@@ -558,13 +608,11 @@ func (h *sentPacketHandler) detectAndRemoveAckedPackets(ack *wire.AckFrame, encL
}
}
if err := pnSpace.history.Remove(p.PacketNumber); err != nil {
- return nil, err
- }
- if h.tracer != nil && h.tracer.AcknowledgedPacket != nil {
- h.tracer.AcknowledgedPacket(encLevel, p.PacketNumber)
+ return nil, false, err
}
}
- return h.ackedPackets, nil
+ // TODO: add support for the transport:packets_acked qlog event
+ return h.ackedPackets, hasAckEliciting, nil
}
func (h *sentPacketHandler) getLossTimeAndSpace() (monotime.Time, protocol.EncryptionLevel) {
@@ -653,13 +701,20 @@ func (h *sentPacketHandler) setLossDetectionTimer(now monotime.Time) {
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.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeCancelled,
+ })
}
}
- if hasAlarm && h.tracer != nil && h.tracer.SetLossTimer != nil && newAlarm != oldAlarm {
- h.tracer.SetLossTimer(newAlarm.TimerType, newAlarm.EncryptionLevel, newAlarm.Time.ToTime())
+ if h.qlogger != nil && hasAlarm && newAlarm != oldAlarm {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeSet,
+ TimerType: newAlarm.TimerType,
+ EncLevel: newAlarm.EncryptionLevel,
+ Time: newAlarm.Time.ToTime(),
+ })
}
}
@@ -687,7 +742,7 @@ func (h *sentPacketHandler) lossDetectionTime(now monotime.Time) alarmTimer {
if !lossTime.IsZero() && (pathProbeLossTime.IsZero() || lossTime.Before(pathProbeLossTime)) {
return alarmTimer{
Time: lossTime,
- TimerType: logging.TimerTypeACK,
+ TimerType: qlog.TimerTypeACK,
EncryptionLevel: encLevel,
}
}
@@ -695,14 +750,14 @@ func (h *sentPacketHandler) lossDetectionTime(now monotime.Time) alarmTimer {
if !ptoTime.IsZero() && (pathProbeLossTime.IsZero() || ptoTime.Before(pathProbeLossTime)) {
return alarmTimer{
Time: ptoTime,
- TimerType: logging.TimerTypePTO,
+ TimerType: qlog.TimerTypePTO,
EncryptionLevel: encLevel,
}
}
if !pathProbeLossTime.IsZero() {
return alarmTimer{
Time: pathProbeLossTime,
- TimerType: logging.TimerTypePathProbe,
+ TimerType: qlog.TimerTypePathProbe,
EncryptionLevel: protocol.Encryption1RTT,
}
}
@@ -751,22 +806,34 @@ func (h *sentPacketHandler) detectLostPackets(now monotime.Time, encLevel protoc
var packetLost bool
if !p.SendTime.After(lostSendTime) {
packetLost = true
- if !p.isPathProbePacket {
+ if !p.isPathProbePacket && p.IsAckEliciting() {
if h.logger.Debug() {
h.logger.Debugf("\tlost packet %d (time threshold)", pn)
}
- if h.tracer != nil && h.tracer.LostPacket != nil {
- h.tracer.LostPacket(p.EncryptionLevel, pn, logging.PacketLossTimeThreshold)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.PacketLost{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.EncryptionLevelToPacketType(p.EncryptionLevel),
+ PacketNumber: pn,
+ },
+ Trigger: qlog.PacketLossTimeThreshold,
+ })
}
}
} else if pnSpace.history.Difference(pnSpace.largestAcked, pn) >= packetThreshold {
packetLost = true
- if !p.isPathProbePacket {
+ if !p.isPathProbePacket && p.IsAckEliciting() {
if h.logger.Debug() {
h.logger.Debugf("\tlost packet %d (reordering threshold)", pn)
}
- if h.tracer != nil && h.tracer.LostPacket != nil {
- h.tracer.LostPacket(p.EncryptionLevel, pn, logging.PacketLossReorderingThreshold)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.PacketLost{
+ Header: qlog.PacketHeader{
+ PacketType: qlog.EncryptionLevelToPacketType(p.EncryptionLevel),
+ PacketNumber: pn,
+ },
+ Trigger: qlog.PacketLossReorderingThreshold,
+ })
}
}
} else if pnSpace.lossTime.IsZero() {
@@ -782,7 +849,7 @@ func (h *sentPacketHandler) detectLostPackets(now monotime.Time, encLevel protoc
h.lostPackets.Add(pn, p.SendTime)
}
pnSpace.history.DeclareLost(pn)
- if !p.isPathProbePacket {
+ if !p.isPathProbePacket && p.IsAckEliciting() {
// the bytes in flight need to be reduced no matter if the frames in this packet will be retransmitted
h.removeFromBytesInFlight(p)
h.queueFramesForRetransmission(p)
@@ -809,8 +876,12 @@ func (h *sentPacketHandler) OnLossDetectionTimeout(now monotime.Time) error {
if h.logger.Debug() {
h.logger.Debugf("Loss detection alarm fired in loss timer mode. Loss time: %s", earliestLossTime)
}
- if h.tracer != nil && h.tracer.LossTimerExpired != nil {
- h.tracer.LossTimerExpired(logging.TimerTypeACK, encLevel)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeExpired,
+ TimerType: qlog.TimerTypeACK,
+ EncLevel: encLevel,
+ })
}
// Early retransmit or time loss detection
h.detectLostPackets(now, encLevel)
@@ -847,13 +918,13 @@ func (h *sentPacketHandler) OnLossDetectionTimeout(now monotime.Time) error {
if h.logger.Debug() {
h.logger.Debugf("Loss detection alarm for %s fired in PTO mode. PTO count: %d", encLevel, h.ptoCount)
}
- if h.tracer != nil {
- if h.tracer.LossTimerExpired != nil {
- h.tracer.LossTimerExpired(logging.TimerTypePTO, encLevel)
- }
- if h.tracer.UpdatedPTOCount != nil {
- h.tracer.UpdatedPTOCount(h.ptoCount)
- }
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeExpired,
+ TimerType: qlog.TimerTypePTO,
+ EncLevel: encLevel,
+ })
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: h.ptoCount})
}
h.numProbesToSend += 2
//nolint:exhaustive // We never arm a PTO timer for 0-RTT packets.
@@ -973,11 +1044,12 @@ func (h *sentPacketHandler) QueueProbePacket(encLevel protocol.EncryptionLevel)
if p == nil {
return false
}
- h.queueFramesForRetransmission(p)
// TODO: don't declare the packet lost here.
// Keep track of acknowledged frames instead.
- h.removeFromBytesInFlight(p)
+ // Call DeclareLost before queueFramesForRetransmission, which clears the packet's frames.
pnSpace.history.DeclareLost(pn)
+ h.removeFromBytesInFlight(p)
+ h.queueFramesForRetransmission(p)
return true
}
@@ -1006,14 +1078,14 @@ func (h *sentPacketHandler) ResetForRetry(now monotime.Time) {
if firstPacketSendTime.IsZero() {
firstPacketSendTime = p.SendTime
}
- if !p.declaredLost {
+ if p.IsAckEliciting() {
h.queueFramesForRetransmission(p)
}
}
// All application data packets sent at this point are 0-RTT packets.
// In the case of a Retry, we can assume that the server dropped all of them.
for _, p := range h.appDataPackets.history.Packets() {
- if !p.declaredLost {
+ if p.IsAckEliciting() {
h.queueFramesForRetransmission(p)
}
}
@@ -1026,20 +1098,20 @@ func (h *sentPacketHandler) ResetForRetry(now monotime.Time) {
if h.logger.Debug() {
h.logger.Debugf("\tupdated RTT: %s (σ: %s)", h.rttStats.SmoothedRTT(), h.rttStats.MeanDeviation())
}
- if h.tracer != nil && h.tracer.UpdatedMetrics != nil {
- h.tracer.UpdatedMetrics(h.rttStats, h.congestion.GetCongestionWindow(), h.bytesInFlight, h.packetsInFlight())
+ if h.qlogger != nil {
+ h.qlogMetricsUpdated()
}
}
h.initialPackets = newPacketNumberSpace(h.initialPackets.pns.Peek(), false)
h.appDataPackets = newPacketNumberSpace(h.appDataPackets.pns.Peek(), true)
oldAlarm := h.alarm
h.alarm = alarmTimer{}
- if h.tracer != nil {
- if h.tracer.UpdatedPTOCount != nil {
- h.tracer.UpdatedPTOCount(0)
- }
- if !oldAlarm.Time.IsZero() && h.tracer.LossTimerCanceled != nil {
- h.tracer.LossTimerCanceled()
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
+ if !oldAlarm.Time.IsZero() {
+ h.qlogger.RecordEvent(qlog.LossTimerUpdated{
+ Type: qlog.LossTimerUpdateTypeCancelled,
+ })
}
}
h.ptoCount = 0
@@ -1051,7 +1123,9 @@ func (h *sentPacketHandler) MigratedPath(now monotime.Time, initialMaxDatagramSi
h.appDataPackets.history.DeclareLost(pn)
if !p.isPathProbePacket {
h.removeFromBytesInFlight(p)
- h.queueFramesForRetransmission(p)
+ if p.IsAckEliciting() {
+ h.queueFramesForRetransmission(p)
+ }
}
}
for pn := range h.appDataPackets.history.PathProbes() {
@@ -1063,7 +1137,7 @@ func (h *sentPacketHandler) MigratedPath(now monotime.Time, initialMaxDatagramSi
h.connStats,
initialMaxDatagramSize,
true, // use Reno
- h.tracer,
+ h.qlogger,
)
h.setLossDetectionTimer(now)
}
diff --git a/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
index 54b74cf745..1500e1cdf7 100644
--- a/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
+++ b/vendor/github.com/quic-go/quic-go/internal/ackhandler/sent_packet_history.go
@@ -58,17 +58,10 @@ func (h *sentPacketHistory) SkippedPacket(pn protocol.PacketNumber) {
h.skippedPackets = append(h.skippedPackets, pn)
}
-func (h *sentPacketHistory) SentNonAckElicitingPacket(pn protocol.PacketNumber) {
- h.checkSequentialPacketNumberUse(pn)
- if len(h.packets) > 0 {
- h.packets = append(h.packets, nil)
- }
-}
-
-func (h *sentPacketHistory) SentAckElicitingPacket(pn protocol.PacketNumber, p *packet) {
+func (h *sentPacketHistory) SentPacket(pn protocol.PacketNumber, p *packet) {
h.checkSequentialPacketNumberUse(pn)
h.packets = append(h.packets, p)
- if p.outstanding() {
+ if p.Outstanding() {
h.numOutstanding++
}
}
@@ -111,7 +104,7 @@ func (h *sentPacketHistory) FirstOutstanding() (protocol.PacketNumber, *packet)
return protocol.InvalidPacketNumber, nil
}
for i, p := range h.packets {
- if p != nil && p.outstanding() {
+ if p != nil && p.Outstanding() {
return h.firstPacketNumber + protocol.PacketNumber(i), p
}
}
@@ -140,6 +133,10 @@ func (h *sentPacketHistory) Len() int {
return len(h.packets)
}
+func (h *sentPacketHistory) NumOutstanding() int {
+ return h.numOutstanding
+}
+
// Remove removes a packet from the sent packet history.
// It must not be used for skipped packet numbers.
func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
@@ -148,7 +145,7 @@ func (h *sentPacketHistory) Remove(pn protocol.PacketNumber) error {
return fmt.Errorf("packet %d not found in sent packet history", pn)
}
p := h.packets[idx]
- if p.outstanding() {
+ if p.Outstanding() {
h.numOutstanding--
if h.numOutstanding < 0 {
panic("negative number of outstanding packets")
@@ -243,7 +240,7 @@ func (h *sentPacketHistory) DeclareLost(pn protocol.PacketNumber) {
return
}
p := h.packets[idx]
- if p.outstanding() {
+ if p.Outstanding() {
h.numOutstanding--
if h.numOutstanding < 0 {
panic("negative number of outstanding packets")
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go b/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go
index 1d03abbb8a..3ad827d2b2 100644
--- a/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/bandwidth.go
@@ -1,7 +1,6 @@
package congestion
import (
- "math"
"time"
"github.com/quic-go/quic-go/internal/protocol"
@@ -10,8 +9,6 @@ import (
// Bandwidth of a connection
type Bandwidth uint64
-const infBandwidth Bandwidth = math.MaxUint64
-
const (
// BitsPerSecond is 1 bit per second
BitsPerSecond Bandwidth = 1
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go b/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
index 1ae10390ae..e5457ddb81 100644
--- a/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/cubic_sender.go
@@ -6,7 +6,8 @@ import (
"github.com/quic-go/quic-go/internal/monotime"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
)
const (
@@ -56,8 +57,8 @@ type cubicSender struct {
maxDatagramSize protocol.ByteCount
- lastState logging.CongestionState
- tracer *logging.ConnectionTracer
+ lastState qlog.CongestionState
+ qlogger qlogwriter.Recorder
}
var (
@@ -72,7 +73,7 @@ func NewCubicSender(
connStats *utils.ConnectionStats,
initialMaxDatagramSize protocol.ByteCount,
reno bool,
- tracer *logging.ConnectionTracer,
+ qlogger qlogwriter.Recorder,
) *cubicSender {
return newCubicSender(
clock,
@@ -82,7 +83,7 @@ func NewCubicSender(
initialMaxDatagramSize,
initialCongestionWindow*initialMaxDatagramSize,
protocol.MaxCongestionWindowPackets*initialMaxDatagramSize,
- tracer,
+ qlogger,
)
}
@@ -94,7 +95,7 @@ func newCubicSender(
initialMaxDatagramSize,
initialCongestionWindow,
initialMaxCongestionWindow protocol.ByteCount,
- tracer *logging.ConnectionTracer,
+ qlogger qlogwriter.Recorder,
) *cubicSender {
c := &cubicSender{
rttStats: rttStats,
@@ -109,13 +110,15 @@ func newCubicSender(
cubic: NewCubic(clock),
clock: clock,
reno: reno,
- tracer: tracer,
+ qlogger: qlogger,
maxDatagramSize: initialMaxDatagramSize,
}
c.pacer = newPacer(c.BandwidthEstimate)
- if c.tracer != nil && c.tracer.UpdatedCongestionState != nil {
- c.lastState = logging.CongestionStateSlowStart
- c.tracer.UpdatedCongestionState(logging.CongestionStateSlowStart)
+ if c.qlogger != nil {
+ c.lastState = qlog.CongestionStateSlowStart
+ c.qlogger.RecordEvent(qlog.CongestionStateUpdated{
+ State: qlog.CongestionStateSlowStart,
+ })
}
return c
}
@@ -173,7 +176,7 @@ func (c *cubicSender) MaybeExitSlowStart() {
c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) {
// exit slow start
c.slowStartThreshold = c.congestionWindow
- c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance)
+ c.maybeQlogStateChange(qlog.CongestionStateCongestionAvoidance)
}
}
@@ -203,7 +206,7 @@ func (c *cubicSender) OnCongestionEvent(packetNumber protocol.PacketNumber, lost
return
}
c.lastCutbackExitedSlowstart = c.InSlowStart()
- c.maybeTraceStateChange(logging.CongestionStateRecovery)
+ c.maybeQlogStateChange(qlog.CongestionStateRecovery)
if c.reno {
c.congestionWindow = protocol.ByteCount(float64(c.congestionWindow) * renoBeta)
@@ -232,7 +235,7 @@ func (c *cubicSender) maybeIncreaseCwnd(
// the current window.
if !c.isCwndLimited(priorInFlight) {
c.cubic.OnApplicationLimited()
- c.maybeTraceStateChange(logging.CongestionStateApplicationLimited)
+ c.maybeQlogStateChange(qlog.CongestionStateApplicationLimited)
return
}
if c.congestionWindow >= c.maxCongestionWindow() {
@@ -241,11 +244,11 @@ func (c *cubicSender) maybeIncreaseCwnd(
if c.InSlowStart() {
// TCP slow start, exponential growth, increase by one for each ACK.
c.congestionWindow += c.maxDatagramSize
- c.maybeTraceStateChange(logging.CongestionStateSlowStart)
+ c.maybeQlogStateChange(qlog.CongestionStateSlowStart)
return
}
// Congestion avoidance
- c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance)
+ c.maybeQlogStateChange(qlog.CongestionStateCongestionAvoidance)
if c.reno {
// Classic Reno congestion avoidance.
c.numAckedPackets++
@@ -275,8 +278,8 @@ func (c *cubicSender) isCwndLimited(bytesInFlight protocol.ByteCount) bool {
func (c *cubicSender) BandwidthEstimate() Bandwidth {
srtt := c.rttStats.SmoothedRTT()
if srtt == 0 {
- // If we haven't measured an rtt, the bandwidth estimate is unknown.
- return infBandwidth
+ // This should never happen, but if it does, avoid division by zero.
+ srtt = protocol.TimerGranularity
}
return BandwidthFromDelta(c.GetCongestionWindow(), srtt)
}
@@ -306,11 +309,11 @@ func (c *cubicSender) OnConnectionMigration() {
c.slowStartThreshold = c.initialMaxCongestionWindow
}
-func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) {
- if c.tracer == nil || c.tracer.UpdatedCongestionState == nil || new == c.lastState {
+func (c *cubicSender) maybeQlogStateChange(new qlog.CongestionState) {
+ if c.qlogger == nil || new == c.lastState {
return
}
- c.tracer.UpdatedCongestionState(new)
+ c.qlogger.RecordEvent(qlog.CongestionStateUpdated{State: new})
c.lastState = new
}
diff --git a/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go b/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
index 92757eedac..7656f52968 100644
--- a/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
+++ b/vendor/github.com/quic-go/quic-go/internal/congestion/pacer.go
@@ -1,6 +1,7 @@
package congestion
import (
+ "math"
"time"
"github.com/quic-go/quic-go/internal/monotime"
@@ -48,8 +49,13 @@ func (p *pacer) Budget(now monotime.Time) protocol.ByteCount {
if p.lastSentTime.IsZero() {
return p.maxBurstSize()
}
- budget := p.budgetAtLastSent + (protocol.ByteCount(p.adjustedBandwidth())*protocol.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9
- if budget < 0 { // protect against overflows
+ delta := now.Sub(p.lastSentTime)
+ var added protocol.ByteCount
+ if delta > 0 {
+ added = p.timeScaledBandwidth(uint64(delta.Nanoseconds()))
+ }
+ budget := p.budgetAtLastSent + added
+ if added > 0 && budget < p.budgetAtLastSent {
budget = protocol.MaxByteCount
}
return min(p.maxBurstSize(), budget)
@@ -57,11 +63,30 @@ func (p *pacer) Budget(now monotime.Time) protocol.ByteCount {
func (p *pacer) maxBurstSize() protocol.ByteCount {
return max(
- protocol.ByteCount(uint64((protocol.MinPacingDelay+protocol.TimerGranularity).Nanoseconds())*p.adjustedBandwidth())/1e9,
+ p.timeScaledBandwidth(uint64((protocol.MinPacingDelay + protocol.TimerGranularity).Nanoseconds())),
maxBurstSizePackets*p.maxDatagramSize,
)
}
+// timeScaledBandwidth calculates the number of bytes that may be sent within
+// a given time interval (ns nanoseconds), based on the current bandwidth estimate.
+// It caps the scaled value to the maximum allowed burst and handles overflows.
+func (p *pacer) timeScaledBandwidth(ns uint64) protocol.ByteCount {
+ bw := p.adjustedBandwidth()
+ if bw == 0 {
+ return 0
+ }
+ const nsPerSecond = 1e9
+ maxBurst := maxBurstSizePackets * p.maxDatagramSize
+ var scaled protocol.ByteCount
+ if ns > math.MaxUint64/bw {
+ scaled = maxBurst
+ } else {
+ scaled = protocol.ByteCount(bw * ns / nsPerSecond)
+ }
+ return scaled
+}
+
// TimeUntilSend returns when the next packet should be sent.
// It returns zero if a packet can be sent immediately.
func (p *pacer) TimeUntilSend() monotime.Time {
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go b/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
index 1baf5d6b0b..ce83ab18c7 100644
--- a/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/aead.go
@@ -6,7 +6,7 @@ import (
"github.com/quic-go/quic-go/internal/protocol"
)
-func createAEAD(suite *cipherSuite, trafficSecret []byte, v protocol.Version) *xorNonceAEAD {
+func createAEAD(suite cipherSuite, trafficSecret []byte, v protocol.Version) *xorNonceAEAD {
keyLabel := hkdfLabelKeyV1
ivLabel := hkdfLabelIVV1
if v == protocol.Version2 {
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go b/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
index d8a381daf0..03fe0dad8e 100644
--- a/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/cipher_suite.go
@@ -23,14 +23,14 @@ type cipherSuite struct {
func (s cipherSuite) IVLen() int { return aeadNonceLength }
-func getCipherSuite(id uint16) *cipherSuite {
+func getCipherSuite(id uint16) cipherSuite {
switch id {
case tls.TLS_AES_128_GCM_SHA256:
- return &cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
+ return cipherSuite{ID: tls.TLS_AES_128_GCM_SHA256, Hash: crypto.SHA256, KeyLen: 16, AEAD: aeadAESGCMTLS13}
case tls.TLS_CHACHA20_POLY1305_SHA256:
- return &cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
+ return cipherSuite{ID: tls.TLS_CHACHA20_POLY1305_SHA256, Hash: crypto.SHA256, KeyLen: 32, AEAD: aeadChaCha20Poly1305}
case tls.TLS_AES_256_GCM_SHA384:
- return &cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
+ return cipherSuite{ID: tls.TLS_AES_256_GCM_SHA384, Hash: crypto.SHA384, KeyLen: 32, AEAD: aeadAESGCMTLS13}
default:
panic(fmt.Sprintf("unknown cypher suite: %d", id))
}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go b/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
index d3a9734d2f..d481ac675a 100644
--- a/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/crypto_setup.go
@@ -14,7 +14,8 @@ import (
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/internal/utils"
"github.com/quic-go/quic-go/internal/wire"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
"github.com/quic-go/quic-go/quicvarint"
)
@@ -40,8 +41,8 @@ type cryptoSetup struct {
rttStats *utils.RTTStats
- tracer *logging.ConnectionTracer
- logger utils.Logger
+ qlogger qlogwriter.Recorder
+ logger utils.Logger
perspective protocol.Perspective
@@ -72,7 +73,7 @@ func NewCryptoSetupClient(
tlsConf *tls.Config,
enable0RTT bool,
rttStats *utils.RTTStats,
- tracer *logging.ConnectionTracer,
+ qlogger qlogwriter.Recorder,
logger utils.Logger,
version protocol.Version,
) CryptoSetup {
@@ -80,7 +81,7 @@ func NewCryptoSetupClient(
connID,
tp,
rttStats,
- tracer,
+ qlogger,
logger,
protocol.PerspectiveClient,
version,
@@ -108,7 +109,7 @@ func NewCryptoSetupServer(
tlsConf *tls.Config,
allow0RTT bool,
rttStats *utils.RTTStats,
- tracer *logging.ConnectionTracer,
+ qlogger qlogwriter.Recorder,
logger utils.Logger,
version protocol.Version,
) CryptoSetup {
@@ -116,7 +117,7 @@ func NewCryptoSetupServer(
connID,
tp,
rttStats,
- tracer,
+ qlogger,
logger,
protocol.PerspectiveServer,
version,
@@ -137,24 +138,30 @@ func newCryptoSetup(
connID protocol.ConnectionID,
tp *wire.TransportParameters,
rttStats *utils.RTTStats,
- tracer *logging.ConnectionTracer,
+ qlogger qlogwriter.Recorder,
logger utils.Logger,
perspective protocol.Perspective,
version protocol.Version,
) *cryptoSetup {
initialSealer, initialOpener := NewInitialAEAD(connID, perspective, version)
- if tracer != nil && tracer.UpdatedKeyFromTLS != nil {
- tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
- tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
+ if qlogger != nil {
+ qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveClient),
+ })
+ qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveServer),
+ })
}
return &cryptoSetup{
initialSealer: initialSealer,
initialOpener: initialOpener,
- aead: newUpdatableAEAD(rttStats, tracer, logger, version),
+ aead: newUpdatableAEAD(rttStats, qlogger, logger, version),
events: make([]Event, 0, 16),
ourParams: tp,
rttStats: rttStats,
- tracer: tracer,
+ qlogger: qlogger,
logger: logger,
perspective: perspective,
version: version,
@@ -165,9 +172,15 @@ func (h *cryptoSetup) ChangeConnectionID(id protocol.ConnectionID) {
initialSealer, initialOpener := NewInitialAEAD(id, h.perspective, h.version)
h.initialSealer = initialSealer
h.initialOpener = initialOpener
- if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
- h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveClient)
- h.tracer.UpdatedKeyFromTLS(protocol.EncryptionInitial, protocol.PerspectiveServer)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveClient),
+ })
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveServer),
+ })
}
}
@@ -374,19 +387,29 @@ func (h *cryptoSetup) GetSessionTicket() ([]byte, error) {
// We can't check h.tlsConfig here, since the actual config might have been obtained from
// the GetConfigForClient callback.
// See https://github.com/golang/go/issues/62032.
- // Once that issue is resolved, this error assertion can be removed.
+ // This error assertion can be removed once we drop support for Go 1.25.
if strings.Contains(err.Error(), "session ticket keys unavailable") {
return nil, nil
}
return nil, err
}
- ev := h.conn.NextEvent()
- if ev.Kind != tls.QUICWriteData || ev.Level != tls.QUICEncryptionLevelApplication {
- panic("crypto/tls bug: where's my session ticket?")
- }
- ticket := ev.Data
- if ev := h.conn.NextEvent(); ev.Kind != tls.QUICNoEvent {
- panic("crypto/tls bug: why more than one ticket?")
+ // If session tickets are disabled, NextEvent will immediately return QUICNoEvent,
+ // and we will return a nil ticket.
+ var ticket []byte
+ for {
+ ev := h.conn.NextEvent()
+ if ev.Kind == tls.QUICNoEvent {
+ break
+ }
+ if ev.Kind == tls.QUICWriteData && ev.Level == tls.QUICEncryptionLevelApplication {
+ if ticket != nil {
+ h.logger.Errorf("unexpected multiple session tickets")
+ continue
+ }
+ ticket = ev.Data
+ } else {
+ h.logger.Errorf("unexpected event: %v", ev.Kind)
+ }
}
return ticket, nil
}
@@ -462,8 +485,11 @@ func (h *cryptoSetup) setReadKey(el tls.QUICEncryptionLevel, suiteID uint16, tra
panic("unexpected read encryption level")
}
h.events = append(h.events, Event{Kind: EventReceivedReadKeys})
- if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
- h.tracer.UpdatedKeyFromTLS(protocol.FromTLSEncryptionLevel(el), h.perspective.Opposite())
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.FromTLSEncryptionLevel(el), h.perspective.Opposite()),
+ })
}
}
@@ -482,8 +508,11 @@ func (h *cryptoSetup) setWriteKey(el tls.QUICEncryptionLevel, suiteID uint16, tr
if h.logger.Debug() {
h.logger.Debugf("Installed 0-RTT Write keys (using %s)", tls.CipherSuiteName(suite.ID))
}
- if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
- h.tracer.UpdatedKeyFromTLS(protocol.Encryption0RTT, h.perspective)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.Encryption0RTT, h.perspective),
+ })
}
// don't set used0RTT here. 0-RTT might still get rejected.
return
@@ -506,15 +535,18 @@ func (h *cryptoSetup) setWriteKey(el tls.QUICEncryptionLevel, suiteID uint16, tr
h.used0RTT.Store(true)
h.zeroRTTSealer = nil
h.logger.Debugf("Dropping 0-RTT keys.")
- if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
- h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClient0RTT})
}
}
default:
panic("unexpected write encryption level")
}
- if h.tracer != nil && h.tracer.UpdatedKeyFromTLS != nil {
- h.tracer.UpdatedKeyFromTLS(protocol.FromTLSEncryptionLevel(el), h.perspective)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateTLS,
+ KeyType: encLevelToKeyType(protocol.FromTLSEncryptionLevel(el), h.perspective),
+ })
}
}
@@ -539,6 +571,10 @@ func (h *cryptoSetup) DiscardInitialKeys() {
h.initialSealer = nil
if dropped {
h.logger.Debugf("Dropping Initial keys.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClientInitial})
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeServerInitial})
+ }
}
}
@@ -558,6 +594,10 @@ func (h *cryptoSetup) SetHandshakeConfirmed() {
}
if dropped {
h.logger.Debugf("Dropping Handshake keys.")
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClientHandshake})
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeServerHandshake})
+ }
}
}
@@ -625,8 +665,8 @@ func (h *cryptoSetup) Get1RTTOpener() (ShortHeaderOpener, error) {
if h.zeroRTTOpener != nil && time.Since(h.handshakeCompleteTime) > 3*h.rttStats.PTO(true) {
h.zeroRTTOpener = nil
h.logger.Debugf("Dropping 0-RTT keys.")
- if h.tracer != nil && h.tracer.DroppedEncryptionLevel != nil {
- h.tracer.DroppedEncryptionLevel(protocol.Encryption0RTT)
+ if h.qlogger != nil {
+ h.qlogger.RecordEvent(qlog.KeyDiscarded{KeyType: qlog.KeyTypeClient0RTT})
}
}
@@ -649,3 +689,32 @@ func wrapError(err error) error {
}
return &qerr.TransportError{ErrorCode: qerr.InternalError, ErrorMessage: err.Error()}
}
+
+func encLevelToKeyType(encLevel protocol.EncryptionLevel, pers protocol.Perspective) qlog.KeyType {
+ if pers == protocol.PerspectiveServer {
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return qlog.KeyTypeServerInitial
+ case protocol.EncryptionHandshake:
+ return qlog.KeyTypeServerHandshake
+ case protocol.Encryption0RTT:
+ return qlog.KeyTypeServer0RTT
+ case protocol.Encryption1RTT:
+ return qlog.KeyTypeServer1RTT
+ default:
+ return ""
+ }
+ }
+ switch encLevel {
+ case protocol.EncryptionInitial:
+ return qlog.KeyTypeClientInitial
+ case protocol.EncryptionHandshake:
+ return qlog.KeyTypeClientHandshake
+ case protocol.Encryption0RTT:
+ return qlog.KeyTypeClient0RTT
+ case protocol.Encryption1RTT:
+ return qlog.KeyTypeClient1RTT
+ default:
+ return ""
+ }
+}
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go b/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
index 2c5ee42f12..93c3cd9809 100644
--- a/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/header_protector.go
@@ -24,7 +24,7 @@ func hkdfHeaderProtectionLabel(v protocol.Version) string {
return "quic hp"
}
-func newHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, v protocol.Version) headerProtector {
+func newHeaderProtector(suite cipherSuite, trafficSecret []byte, isLongHeader bool, v protocol.Version) headerProtector {
hkdfLabel := hkdfHeaderProtectionLabel(v)
switch suite.ID {
case tls.TLS_AES_128_GCM_SHA256, tls.TLS_AES_256_GCM_SHA384:
@@ -44,7 +44,7 @@ type aesHeaderProtector struct {
var _ headerProtector = &aesHeaderProtector{}
-func newAESHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
+func newAESHeaderProtector(suite cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
block, err := aes.NewCipher(hpKey)
if err != nil {
@@ -88,7 +88,7 @@ type chachaHeaderProtector struct {
var _ headerProtector = &chachaHeaderProtector{}
-func newChaChaHeaderProtector(suite *cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
+func newChaChaHeaderProtector(suite cipherSuite, trafficSecret []byte, isLongHeader bool, hkdfLabel string) headerProtector {
hpKey := hkdfExpandLabel(suite.Hash, trafficSecret, []byte{}, hkdfLabel, suite.KeyLen)
p := &chachaHeaderProtector{
diff --git a/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go b/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
index ef92ab1c4e..f88f76ad8b 100644
--- a/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
+++ b/vendor/github.com/quic-go/quic-go/internal/handshake/updatable_aead.go
@@ -12,7 +12,8 @@ import (
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/qerr"
"github.com/quic-go/quic-go/internal/utils"
- "github.com/quic-go/quic-go/logging"
+ "github.com/quic-go/quic-go/qlog"
+ "github.com/quic-go/quic-go/qlogwriter"
)
var keyUpdateInterval atomic.Uint64
@@ -31,7 +32,7 @@ func SetKeyUpdateInterval(v uint64) (reset func()) {
var FirstKeyUpdateInterval uint64 = 100
type updatableAEAD struct {
- suite *cipherSuite
+ suite cipherSuite
keyPhase protocol.KeyPhase
largestAcked protocol.PacketNumber
@@ -65,7 +66,7 @@ type updatableAEAD struct {
rttStats *utils.RTTStats
- tracer *logging.ConnectionTracer
+ qlogger qlogwriter.Recorder
logger utils.Logger
version protocol.Version
@@ -78,14 +79,14 @@ var (
_ ShortHeaderSealer = &updatableAEAD{}
)
-func newUpdatableAEAD(rttStats *utils.RTTStats, tracer *logging.ConnectionTracer, logger utils.Logger, version protocol.Version) *updatableAEAD {
+func newUpdatableAEAD(rttStats *utils.RTTStats, qlogger qlogwriter.Recorder, logger utils.Logger, version protocol.Version) *updatableAEAD {
return &updatableAEAD{
firstPacketNumber: protocol.InvalidPacketNumber,
largestAcked: protocol.InvalidPacketNumber,
firstRcvdWithCurrentKey: protocol.InvalidPacketNumber,
firstSentWithCurrentKey: protocol.InvalidPacketNumber,
rttStats: rttStats,
- tracer: tracer,
+ qlogger: qlogger,
logger: logger,
version: version,
}
@@ -94,8 +95,15 @@ func newUpdatableAEAD(rttStats *utils.RTTStats, tracer *logging.ConnectionTracer
func (a *updatableAEAD) rollKeys() {
if a.prevRcvAEAD != nil {
a.logger.Debugf("Dropping key phase %d ahead of scheduled time. Drop time was: %s", a.keyPhase-1, a.prevRcvAEADExpiry)
- if a.tracer != nil && a.tracer.DroppedKey != nil {
- a.tracer.DroppedKey(a.keyPhase - 1)
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
}
a.prevRcvAEADExpiry = 0
}
@@ -128,10 +136,10 @@ func (a *updatableAEAD) getNextTrafficSecret(hash crypto.Hash, ts []byte) []byte
// SetReadKey sets the read key.
// For the client, this function is called before SetWriteKey.
// For the server, this function is called after SetWriteKey.
-func (a *updatableAEAD) SetReadKey(suite *cipherSuite, trafficSecret []byte) {
+func (a *updatableAEAD) SetReadKey(suite cipherSuite, trafficSecret []byte) {
a.rcvAEAD = createAEAD(suite, trafficSecret, a.version)
a.headerDecrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
- if a.suite == nil {
+ if a.suite.ID == 0 { // suite is not set yet
a.setAEADParameters(a.rcvAEAD, suite)
}
@@ -142,10 +150,10 @@ func (a *updatableAEAD) SetReadKey(suite *cipherSuite, trafficSecret []byte) {
// SetWriteKey sets the write key.
// For the client, this function is called after SetReadKey.
// For the server, this function is called before SetReadKey.
-func (a *updatableAEAD) SetWriteKey(suite *cipherSuite, trafficSecret []byte) {
+func (a *updatableAEAD) SetWriteKey(suite cipherSuite, trafficSecret []byte) {
a.sendAEAD = createAEAD(suite, trafficSecret, a.version)
a.headerEncrypter = newHeaderProtector(suite, trafficSecret, false, a.version)
- if a.suite == nil {
+ if a.suite.ID == 0 { // suite is not set yet
a.setAEADParameters(a.sendAEAD, suite)
}
@@ -153,7 +161,7 @@ func (a *updatableAEAD) SetWriteKey(suite *cipherSuite, trafficSecret []byte) {
a.nextSendAEAD = createAEAD(suite, a.nextSendTrafficSecret, a.version)
}
-func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite *cipherSuite) {
+func (a *updatableAEAD) setAEADParameters(aead cipher.AEAD, suite cipherSuite) {
a.nonceBuf = make([]byte, aead.NonceSize())
a.aeadOverhead = aead.Overhead()
a.suite = suite
@@ -190,8 +198,15 @@ func (a *updatableAEAD) open(dst, src []byte, rcvTime monotime.Time, pn protocol
a.prevRcvAEAD = nil
a.logger.Debugf("Dropping key phase %d", a.keyPhase-1)
a.prevRcvAEADExpiry = 0
- if a.tracer != nil && a.tracer.DroppedKey != nil {
- a.tracer.DroppedKey(a.keyPhase - 1)
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
+ a.qlogger.RecordEvent(qlog.KeyDiscarded{
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase - 1,
+ })
}
}
binary.BigEndian.PutUint64(a.nonceBuf[len(a.nonceBuf)-8:], uint64(pn))
@@ -224,8 +239,17 @@ func (a *updatableAEAD) open(dst, src []byte, rcvTime monotime.Time, pn protocol
// The peer initiated this key update. It's safe to drop the keys for the previous generation now.
// Start a timer to drop the previous key generation.
a.startKeyDropTimer(rcvTime)
- if a.tracer != nil && a.tracer.UpdatedKey != nil {
- a.tracer.UpdatedKey(a.keyPhase, true)
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateRemote,
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase,
+ })
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateRemote,
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase,
+ })
}
a.firstRcvdWithCurrentKey = pn
return dec, err
@@ -315,9 +339,17 @@ func (a *updatableAEAD) shouldInitiateKeyUpdate() bool {
func (a *updatableAEAD) KeyPhase() protocol.KeyPhaseBit {
if a.shouldInitiateKeyUpdate() {
a.rollKeys()
- a.logger.Debugf("Initiating key update to key phase %d", a.keyPhase)
- if a.tracer != nil && a.tracer.UpdatedKey != nil {
- a.tracer.UpdatedKey(a.keyPhase, false)
+ if a.qlogger != nil {
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateLocal,
+ KeyType: qlog.KeyTypeClient1RTT,
+ KeyPhase: a.keyPhase,
+ })
+ a.qlogger.RecordEvent(qlog.KeyUpdated{
+ Trigger: qlog.KeyUpdateLocal,
+ KeyType: qlog.KeyTypeServer1RTT,
+ KeyPhase: a.keyPhase,
+ })
}
}
return a.keyPhase.Bit()
diff --git a/vendor/github.com/quic-go/quic-go/internal/protocol/params.go b/vendor/github.com/quic-go/quic-go/internal/protocol/params.go
index fe86317fbb..0861d57fc4 100644
--- a/vendor/github.com/quic-go/quic-go/internal/protocol/params.go
+++ b/vendor/github.com/quic-go/quic-go/internal/protocol/params.go
@@ -112,16 +112,13 @@ const MinStreamFrameSize ByteCount = 128
// we send after the handshake completes.
const MaxPostHandshakeCryptoFrameSize = 1000
-// MaxAckFrameSize is the maximum size for an ACK frame that we write
-// Due to the varint encoding, ACK frames can grow (almost) indefinitely large.
-// The MaxAckFrameSize should be large enough to encode many ACK range,
-// but must ensure that a maximum size ACK frame fits into one packet.
-const MaxAckFrameSize ByteCount = 1000
-
// MaxNumAckRanges is the maximum number of ACK ranges that we send in an ACK frame.
// It also serves as a limit for the packet history.
// If at any point we keep track of more ranges, old ranges are discarded.
-const MaxNumAckRanges = 32
+//
+// This value also guarantees that ACK Range Count value in the ACK frame can be encoded
+// in a single byte varint.
+const MaxNumAckRanges = 64
// MinPacingDelay is the minimum duration that is used for packet pacing
// If the packet packing frequency is higher, multiple packets might be sent at once.
diff --git a/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go b/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
index 61cbef5c3d..2753130732 100644
--- a/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
+++ b/vendor/github.com/quic-go/quic-go/internal/utils/rtt_stats.go
@@ -12,10 +12,11 @@ const (
oneMinusAlpha = 1 - rttAlpha
rttBeta = 0.25
oneMinusBeta = 1 - rttBeta
- // The default RTT used before an RTT sample is taken.
- defaultInitialRTT = 100 * time.Millisecond
)
+// The default RTT used before an RTT sample is taken
+const DefaultInitialRTT = 100 * time.Millisecond
+
// RTTStats provides round-trip statistics
type RTTStats struct {
hasMeasurement bool
@@ -28,6 +29,14 @@ type RTTStats struct {
maxAckDelay atomic.Int64 // nanoseconds
}
+func NewRTTStats() *RTTStats {
+ var rttStats RTTStats
+ rttStats.minRTT.Store(DefaultInitialRTT.Nanoseconds())
+ rttStats.latestRTT.Store(DefaultInitialRTT.Nanoseconds())
+ rttStats.smoothedRTT.Store(DefaultInitialRTT.Nanoseconds())
+ return &rttStats
+}
+
// MinRTT Returns the minRTT for the entire connection.
// May return Zero if no valid updates have occurred.
func (r *RTTStats) MinRTT() time.Duration {
@@ -58,8 +67,8 @@ func (r *RTTStats) MaxAckDelay() time.Duration {
// PTO gets the probe timeout duration.
func (r *RTTStats) PTO(includeMaxAckDelay bool) time.Duration {
- if r.SmoothedRTT() == 0 {
- return 2 * defaultInitialRTT
+ if !r.hasMeasurement {
+ return 2 * DefaultInitialRTT
}
pto := r.SmoothedRTT() + max(4*r.MeanDeviation(), protocol.TimerGranularity)
if includeMaxAckDelay {
@@ -79,9 +88,9 @@ func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration) {
// the client may cause a high ackDelay to result in underestimation of the
// r.minRTT.
minRTT := time.Duration(r.minRTT.Load())
- if minRTT == 0 || minRTT > sendDelta {
+ if !r.hasMeasurement || minRTT > sendDelta {
minRTT = sendDelta
- r.minRTT.Store(int64(sendDelta))
+ r.minRTT.Store(sendDelta.Nanoseconds())
}
// Correct for ackDelay if information received from the peer results in a
@@ -91,21 +100,25 @@ func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration) {
if sample-minRTT >= ackDelay {
sample -= ackDelay
}
- r.latestRTT.Store(int64(sample))
+ r.latestRTT.Store(sample.Nanoseconds())
// First time call.
if !r.hasMeasurement {
r.hasMeasurement = true
- r.smoothedRTT.Store(int64(sample))
- r.meanDeviation.Store(int64(sample / 2))
+ r.smoothedRTT.Store(sample.Nanoseconds())
+ r.meanDeviation.Store(sample.Nanoseconds() / 2)
} else {
smoothedRTT := r.SmoothedRTT()
meanDev := time.Duration(oneMinusBeta*float32(r.MeanDeviation()/time.Microsecond)+rttBeta*float32((smoothedRTT-sample).Abs()/time.Microsecond)) * time.Microsecond
newSmoothedRTT := time.Duration((float32(smoothedRTT/time.Microsecond)*oneMinusAlpha)+(float32(sample/time.Microsecond)*rttAlpha)) * time.Microsecond
- r.meanDeviation.Store(int64(meanDev))
- r.smoothedRTT.Store(int64(newSmoothedRTT))
+ r.meanDeviation.Store(meanDev.Nanoseconds())
+ r.smoothedRTT.Store(newSmoothedRTT.Nanoseconds())
}
}
+func (r *RTTStats) HasMeasurement() bool {
+ return r.hasMeasurement
+}
+
// SetMaxAckDelay sets the max_ack_delay
func (r *RTTStats) SetMaxAckDelay(mad time.Duration) {
r.maxAckDelay.Store(int64(mad))
@@ -127,9 +140,9 @@ func (r *RTTStats) SetInitialRTT(t time.Duration) {
func (r *RTTStats) ResetForPathMigration() {
r.hasMeasurement = false
- r.minRTT.Store(0)
- r.latestRTT.Store(0)
- r.smoothedRTT.Store(0)
+ r.minRTT.Store(DefaultInitialRTT.Nanoseconds())
+ r.latestRTT.Store(DefaultInitialRTT.Nanoseconds())
+ r.smoothedRTT.Store(DefaultInitialRTT.Nanoseconds())
r.meanDeviation.Store(0)
// max_ack_delay remains valid
}
diff --git a/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go b/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
index 68bebfa791..191e15307c 100644
--- a/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
+++ b/vendor/github.com/quic-go/quic-go/internal/wire/ack_frame.go
@@ -64,7 +64,7 @@ func parseAckFrame(frame *AckFrame, b []byte, typ FrameType, ackDelayExponent ui
frame.AckRanges = append(frame.AckRanges, AckRange{Smallest: smallest, Largest: largestAcked})
// read all the other ACK ranges
- for i := uint64(0); i < numBlocks; i++ {
+ for range numBlocks {
g, l, err := quicvarint.Parse(b)
if err != nil {
return 0, replaceUnexpectedEOF(err)
@@ -129,7 +129,7 @@ func (f *AckFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
b = quicvarint.Append(b, uint64(f.LargestAcked()))
b = quicvarint.Append(b, encodeAckDelay(f.DelayTime))
- numRanges := f.numEncodableAckRanges()
+ numRanges := min(len(f.AckRanges), protocol.MaxNumAckRanges)
b = quicvarint.Append(b, uint64(numRanges-1))
// write the first range
@@ -154,46 +154,69 @@ func (f *AckFrame) Append(b []byte, _ protocol.Version) ([]byte, error) {
// Length of a written frame
func (f *AckFrame) Length(_ protocol.Version) protocol.ByteCount {
largestAcked := f.AckRanges[0].Largest
- numRanges := f.numEncodableAckRanges()
- length := 1 + quicvarint.Len(uint64(largestAcked)) + quicvarint.Len(encodeAckDelay(f.DelayTime))
+ // The number of ACK ranges is limited to 64, which guarantees that the
+ // ACK Range Count value can be encoded in a single byte varint.
+ length := 1 + quicvarint.Len(uint64(largestAcked)) + quicvarint.Len(encodeAckDelay(f.DelayTime)) + 1
- length += quicvarint.Len(uint64(numRanges - 1))
lowestInFirstRange := f.AckRanges[0].Smallest
length += quicvarint.Len(uint64(largestAcked - lowestInFirstRange))
- for i := 1; i < numRanges; i++ {
+ for i := 1; i < min(len(f.AckRanges), protocol.MaxNumAckRanges); i++ {
gap, len := f.encodeAckRange(i)
length += quicvarint.Len(gap)
length += quicvarint.Len(len)
}
if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
- length += quicvarint.Len(f.ECT0)
- length += quicvarint.Len(f.ECT1)
- length += quicvarint.Len(f.ECNCE)
+ length += quicvarint.Len(f.ECT0) + quicvarint.Len(f.ECT1) + quicvarint.Len(f.ECNCE)
}
return protocol.ByteCount(length)
}
+// Truncate truncates the ACK frame to fit into maxSize,
+// and to at most 64 ACK ranges.
+// maxSize must be large enough to fit at least one ACK range.
+func (f *AckFrame) Truncate(maxSize protocol.ByteCount, _ protocol.Version) {
+ f.AckRanges = f.AckRanges[:f.numEncodableAckRanges(maxSize)]
+}
+
// gets the number of ACK ranges that can be encoded
-// such that the resulting frame is smaller than the maximum ACK frame size
-func (f *AckFrame) numEncodableAckRanges() int {
- length := 1 + quicvarint.Len(uint64(f.LargestAcked())) + quicvarint.Len(encodeAckDelay(f.DelayTime))
- length += 2 // assume that the number of ranges will consume 2 bytes
- for i := 1; i < len(f.AckRanges); i++ {
- gap, len := f.encodeAckRange(i)
- rangeLen := quicvarint.Len(gap) + quicvarint.Len(len)
- if protocol.ByteCount(length+rangeLen) > protocol.MaxAckFrameSize {
- // Writing range i would exceed the MaxAckFrameSize.
- // So encode one range less than that.
- return i - 1
+// such that the resulting frame is smaller than maxSize
+func (f *AckFrame) numEncodableAckRanges(maxSize protocol.ByteCount) int {
+ // Fast path: Most ACK frames are relatively small, and we don't need to calculate the exact length.
+ // We just assume the worst case scenario: every varint is encoded to 8 bytes.
+ // If the result is still smaller than the maximum ACK frame size, the actual ACK frame will definitely fit.
+ length := 1 + 8 /* largest acked */ + 8 /* delay */ + 1 /* ack range count */ + 8 /* first range */
+ if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
+ length += 8 + 8 + 8
+ }
+ numRanges := min(len(f.AckRanges), protocol.MaxNumAckRanges)
+ length += 2 * 8 * (numRanges - 1)
+ if protocol.ByteCount(length) <= maxSize {
+ return numRanges
+ }
+
+ // Slow path: Calculate the exact length of the ACK frame.
+ length = 1 + quicvarint.Len(uint64(f.LargestAcked())) + quicvarint.Len(encodeAckDelay(f.DelayTime)) + 1
+ _, firstRange := f.encodeAckRange(0)
+ length += quicvarint.Len(firstRange)
+ if f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0 {
+ length += quicvarint.Len(f.ECT0) + quicvarint.Len(f.ECT1) + quicvarint.Len(f.ECNCE)
+ }
+ for i := 1; i < numRanges; i++ {
+ gap, l := f.encodeAckRange(i)
+ rangeLen := quicvarint.Len(gap) + quicvarint.Len(l)
+ if protocol.ByteCount(length+rangeLen) > maxSize {
+ // Writing range i would exceed the maximum size,
+ // so encode one range less than that.
+ return i
}
length += rangeLen
}
- return len(f.AckRanges)
+ return numRanges
}
-func (f *AckFrame) encodeAckRange(i int) (uint64 /* gap */, uint64 /* length */) {
+func (f *AckFrame) encodeAckRange(i int) (gap, length uint64) {
if i == 0 {
return 0, uint64(f.AckRanges[0].Largest - f.AckRanges[0].Smallest)
}
@@ -218,7 +241,7 @@ func (f *AckFrame) validateAckRanges() bool {
}
}
- // check the consistency for ACK with multiple NACK ranges
+ // check the consistency for ACK with multiple ACK ranges
for i, ackRange := range f.AckRanges {
if i == 0 {
continue
diff --git a/vendor/github.com/quic-go/quic-go/logging/connection_tracer.go b/vendor/github.com/quic-go/quic-go/logging/connection_tracer.go
deleted file mode 100644
index d6c2b48dc7..0000000000
--- a/vendor/github.com/quic-go/quic-go/logging/connection_tracer.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package logging
-
-import (
- "net"
- "time"
-)
-
-//go:generate go run generate_multiplexer.go ConnectionTracer connection_tracer.go multiplexer.tmpl connection_tracer_multiplexer.go
-
-// A ConnectionTracer records events.
-type ConnectionTracer struct {
- StartedConnection func(local, remote net.Addr, srcConnID, destConnID ConnectionID)
- NegotiatedVersion func(chosen Version, clientVersions, serverVersions []Version)
- ClosedConnection func(err error)
- SentTransportParameters func(parameters *TransportParameters)
- ReceivedTransportParameters func(parameters *TransportParameters)
- RestoredTransportParameters func(parameters *TransportParameters) // for 0-RTT
- SentLongHeaderPacket func(hdr *ExtendedHeader, size ByteCount, ecn ECN, ack *AckFrame, frames []Frame)
- SentShortHeaderPacket func(hdr *ShortHeader, size ByteCount, ecn ECN, ack *AckFrame, frames []Frame)
- ReceivedVersionNegotiationPacket func(dest, src ArbitraryLenConnectionID, versions []Version)
- ReceivedRetry func(hdr *Header)
- ReceivedLongHeaderPacket func(hdr *ExtendedHeader, size ByteCount, ecn ECN, frames []Frame)
- ReceivedShortHeaderPacket func(hdr *ShortHeader, size ByteCount, ecn ECN, frames []Frame)
- BufferedPacket func(packetType PacketType, size ByteCount)
- DroppedPacket func(packetType PacketType, pn PacketNumber, size ByteCount, reason PacketDropReason)
- UpdatedMetrics func(rttStats *RTTStats, cwnd, bytesInFlight ByteCount, packetsInFlight int)
- AcknowledgedPacket func(encLevel EncryptionLevel, pn PacketNumber)
- LostPacket func(encLevel EncryptionLevel, pn PacketNumber, reason PacketLossReason)
- DetectedSpuriousLoss func(encLevel EncryptionLevel, pn PacketNumber, reordering uint64, dur time.Duration)
- UpdatedMTU func(mtu ByteCount, done bool)
- UpdatedCongestionState func(state CongestionState)
- UpdatedPTOCount func(value uint32)
- UpdatedKeyFromTLS func(encLevel EncryptionLevel, p Perspective)
- UpdatedKey func(keyPhase KeyPhase, remote bool)
- DroppedEncryptionLevel func(encLevel EncryptionLevel)
- DroppedKey func(keyPhase KeyPhase)
- SetLossTimer func(timerType TimerType, encLevel EncryptionLevel, time time.Time)
- LossTimerExpired func(timerType TimerType, encLevel EncryptionLevel)
- LossTimerCanceled func()
- ECNStateUpdated func(state ECNState, trigger ECNStateTrigger)
- ChoseALPN func(protocol string)
- // Close is called when the connection is closed.
- Close func()
- Debug func(name, msg string)
-}
diff --git a/vendor/github.com/quic-go/quic-go/logging/connection_tracer_multiplexer.go b/vendor/github.com/quic-go/quic-go/logging/connection_tracer_multiplexer.go
deleted file mode 100644
index 48ac1d38f4..0000000000
--- a/vendor/github.com/quic-go/quic-go/logging/connection_tracer_multiplexer.go
+++ /dev/null
@@ -1,243 +0,0 @@
-// Code generated by generate_multiplexer.go; DO NOT EDIT.
-
-package logging
-
-import (
- "net"
- "time"
-)
-
-func NewMultiplexedConnectionTracer(tracers ...*ConnectionTracer) *ConnectionTracer {
- if len(tracers) == 0 {
- return nil
- }
- if len(tracers) == 1 {
- return tracers[0]
- }
- return &ConnectionTracer{
- StartedConnection: func(local net.Addr, remote net.Addr, srcConnID ConnectionID, destConnID ConnectionID) {
- for _, t := range tracers {
- if t.StartedConnection != nil {
- t.StartedConnection(local, remote, srcConnID, destConnID)
- }
- }
- },
- NegotiatedVersion: func(chosen Version, clientVersions []Version, serverVersions []Version) {
- for _, t := range tracers {
- if t.NegotiatedVersion != nil {
- t.NegotiatedVersion(chosen, clientVersions, serverVersions)
- }
- }
- },
- ClosedConnection: func(err error) {
- for _, t := range tracers {
- if t.ClosedConnection != nil {
- t.ClosedConnection(err)
- }
- }
- },
- SentTransportParameters: func(parameters *TransportParameters) {
- for _, t := range tracers {
- if t.SentTransportParameters != nil {
- t.SentTransportParameters(parameters)
- }
- }
- },
- ReceivedTransportParameters: func(parameters *TransportParameters) {
- for _, t := range tracers {
- if t.ReceivedTransportParameters != nil {
- t.ReceivedTransportParameters(parameters)
- }
- }
- },
- RestoredTransportParameters: func(parameters *TransportParameters) {
- for _, t := range tracers {
- if t.RestoredTransportParameters != nil {
- t.RestoredTransportParameters(parameters)
- }
- }
- },
- SentLongHeaderPacket: func(hdr *ExtendedHeader, size ByteCount, ecn ECN, ack *AckFrame, frames []Frame) {
- for _, t := range tracers {
- if t.SentLongHeaderPacket != nil {
- t.SentLongHeaderPacket(hdr, size, ecn, ack, frames)
- }
- }
- },
- SentShortHeaderPacket: func(hdr *ShortHeader, size ByteCount, ecn ECN, ack *AckFrame, frames []Frame) {
- for _, t := range tracers {
- if t.SentShortHeaderPacket != nil {
- t.SentShortHeaderPacket(hdr, size, ecn, ack, frames)
- }
- }
- },
- ReceivedVersionNegotiationPacket: func(dest ArbitraryLenConnectionID, src ArbitraryLenConnectionID, versions []Version) {
- for _, t := range tracers {
- if t.ReceivedVersionNegotiationPacket != nil {
- t.ReceivedVersionNegotiationPacket(dest, src, versions)
- }
- }
- },
- ReceivedRetry: func(hdr *Header) {
- for _, t := range tracers {
- if t.ReceivedRetry != nil {
- t.ReceivedRetry(hdr)
- }
- }
- },
- ReceivedLongHeaderPacket: func(hdr *ExtendedHeader, size ByteCount, ecn ECN, frames []Frame) {
- for _, t := range tracers {
- if t.ReceivedLongHeaderPacket != nil {
- t.ReceivedLongHeaderPacket(hdr, size, ecn, frames)
- }
- }
- },
- ReceivedShortHeaderPacket: func(hdr *ShortHeader, size ByteCount, ecn ECN, frames []Frame) {
- for _, t := range tracers {
- if t.ReceivedShortHeaderPacket != nil {
- t.ReceivedShortHeaderPacket(hdr, size, ecn, frames)
- }
- }
- },
- BufferedPacket: func(packetType PacketType, size ByteCount) {
- for _, t := range tracers {
- if t.BufferedPacket != nil {
- t.BufferedPacket(packetType, size)
- }
- }
- },
- DroppedPacket: func(packetType PacketType, pn PacketNumber, size ByteCount, reason PacketDropReason) {
- for _, t := range tracers {
- if t.DroppedPacket != nil {
- t.DroppedPacket(packetType, pn, size, reason)
- }
- }
- },
- UpdatedMetrics: func(rttStats *RTTStats, cwnd ByteCount, bytesInFlight ByteCount, packetsInFlight int) {
- for _, t := range tracers {
- if t.UpdatedMetrics != nil {
- t.UpdatedMetrics(rttStats, cwnd, bytesInFlight, packetsInFlight)
- }
- }
- },
- AcknowledgedPacket: func(encLevel EncryptionLevel, pn PacketNumber) {
- for _, t := range tracers {
- if t.AcknowledgedPacket != nil {
- t.AcknowledgedPacket(encLevel, pn)
- }
- }
- },
- LostPacket: func(encLevel EncryptionLevel, pn PacketNumber, reason PacketLossReason) {
- for _, t := range tracers {
- if t.LostPacket != nil {
- t.LostPacket(encLevel, pn, reason)
- }
- }
- },
- DetectedSpuriousLoss: func(encLevel EncryptionLevel, pn PacketNumber, reordering uint64, dur time.Duration) {
- for _, t := range tracers {
- if t.DetectedSpuriousLoss != nil {
- t.DetectedSpuriousLoss(encLevel, pn, reordering, dur)
- }
- }
- },
- UpdatedMTU: func(mtu ByteCount, done bool) {
- for _, t := range tracers {
- if t.UpdatedMTU != nil {
- t.UpdatedMTU(mtu, done)
- }
- }
- },
- UpdatedCongestionState: func(state CongestionState) {
- for _, t := range tracers {
- if t.UpdatedCongestionState != nil {
- t.UpdatedCongestionState(state)
- }
- }
- },
- UpdatedPTOCount: func(value uint32) {
- for _, t := range tracers {
- if t.UpdatedPTOCount != nil {
- t.UpdatedPTOCount(value)
- }
- }
- },
- UpdatedKeyFromTLS: func(encLevel EncryptionLevel, p Perspective) {
- for _, t := range tracers {
- if t.UpdatedKeyFromTLS != nil {
- t.UpdatedKeyFromTLS(encLevel, p)
- }
- }
- },
- UpdatedKey: func(keyPhase KeyPhase, remote bool) {
- for _, t := range tracers {
- if t.UpdatedKey != nil {
- t.UpdatedKey(keyPhase, remote)
- }
- }
- },
- DroppedEncryptionLevel: func(encLevel EncryptionLevel) {
- for _, t := range tracers {
- if t.DroppedEncryptionLevel != nil {
- t.DroppedEncryptionLevel(encLevel)
- }
- }
- },
- DroppedKey: func(keyPhase KeyPhase) {
- for _, t := range tracers {
- if t.DroppedKey != nil {
- t.DroppedKey(keyPhase)
- }
- }
- },
- SetLossTimer: func(timerType TimerType, encLevel EncryptionLevel, time time.Time) {
- for _, t := range tracers {
- if t.SetLossTimer != nil {
- t.SetLossTimer(timerType, encLevel, time)
- }
- }
- },
- LossTimerExpired: func(timerType TimerType, encLevel EncryptionLevel) {
- for _, t := range tracers {
- if t.LossTimerExpired != nil {
- t.LossTimerExpired(timerType, encLevel)
- }
- }
- },
- LossTimerCanceled: func() {
- for _, t := range tracers {
- if t.LossTimerCanceled != nil {
- t.LossTimerCanceled()
- }
- }
- },
- ECNStateUpdated: func(state ECNState, trigger ECNStateTrigger) {
- for _, t := range tracers {
- if t.ECNStateUpdated != nil {
- t.ECNStateUpdated(state, trigger)
- }
- }
- },
- ChoseALPN: func(protocol string) {
- for _, t := range tracers {
- if t.ChoseALPN != nil {
- t.ChoseALPN(protocol)
- }
- }
- },
- Close: func() {
- for _, t := range tracers {
- if t.Close != nil {
- t.Close()
- }
- }
- },
- Debug: func(name string, msg string) {
- for _, t := range tracers {
- if t.Debug != nil {
- t.Debug(name, msg)
- }
- }
- },
- }
-}
diff --git a/vendor/github.com/quic-go/quic-go/logging/frame.go b/vendor/github.com/quic-go/quic-go/logging/frame.go
deleted file mode 100644
index e5721eff53..0000000000
--- a/vendor/github.com/quic-go/quic-go/logging/frame.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package logging
-
-import "github.com/quic-go/quic-go/internal/wire"
-
-// A Frame is a QUIC frame
-type Frame any
-
-// The AckRange is used within the AckFrame.
-// It is a range of packet numbers that is being acknowledged.
-type AckRange = wire.AckRange
-
-type (
- // An AckFrame is an ACK frame.
- AckFrame = wire.AckFrame
- // A ConnectionCloseFrame is a CONNECTION_CLOSE frame.
- ConnectionCloseFrame = wire.ConnectionCloseFrame
- // A DataBlockedFrame is a DATA_BLOCKED frame.
- DataBlockedFrame = wire.DataBlockedFrame
- // A HandshakeDoneFrame is a HANDSHAKE_DONE frame.
- HandshakeDoneFrame = wire.HandshakeDoneFrame
- // A MaxDataFrame is a MAX_DATA frame.
- MaxDataFrame = wire.MaxDataFrame
- // A MaxStreamDataFrame is a MAX_STREAM_DATA frame.
- MaxStreamDataFrame = wire.MaxStreamDataFrame
- // A MaxStreamsFrame is a MAX_STREAMS_FRAME.
- MaxStreamsFrame = wire.MaxStreamsFrame
- // A NewConnectionIDFrame is a NEW_CONNECTION_ID frame.
- NewConnectionIDFrame = wire.NewConnectionIDFrame
- // A NewTokenFrame is a NEW_TOKEN frame.
- NewTokenFrame = wire.NewTokenFrame
- // A PathChallengeFrame is a PATH_CHALLENGE frame.
- PathChallengeFrame = wire.PathChallengeFrame
- // A PathResponseFrame is a PATH_RESPONSE frame.
- PathResponseFrame = wire.PathResponseFrame
- // A PingFrame is a PING frame.
- PingFrame = wire.PingFrame
- // A ResetStreamFrame is a RESET_STREAM frame.
- ResetStreamFrame = wire.ResetStreamFrame
- // A RetireConnectionIDFrame is a RETIRE_CONNECTION_ID frame.
- RetireConnectionIDFrame = wire.RetireConnectionIDFrame
- // A StopSendingFrame is a STOP_SENDING frame.
- StopSendingFrame = wire.StopSendingFrame
- // A StreamsBlockedFrame is a STREAMS_BLOCKED frame.
- StreamsBlockedFrame = wire.StreamsBlockedFrame
- // A StreamDataBlockedFrame is a STREAM_DATA_BLOCKED frame.
- StreamDataBlockedFrame = wire.StreamDataBlockedFrame
- // An AckFrequencyFrame is an ACK_FREQUENCY frame.
- AckFrequencyFrame = wire.AckFrequencyFrame
- // An ImmediateAckFrame is an IMMEDIATE_ACK frame.
- ImmediateAckFrame = wire.ImmediateAckFrame
-)
-
-// A CryptoFrame is a CRYPTO frame.
-type CryptoFrame struct {
- Offset ByteCount
- Length ByteCount
-}
-
-// A StreamFrame is a STREAM frame.
-type StreamFrame struct {
- StreamID StreamID
- Offset ByteCount
- Length ByteCount
- Fin bool
-}
-
-// A DatagramFrame is a DATAGRAM frame.
-type DatagramFrame struct {
- Length ByteCount
-}
diff --git a/vendor/github.com/quic-go/quic-go/logging/generate_multiplexer.go b/vendor/github.com/quic-go/quic-go/logging/generate_multiplexer.go
deleted file mode 100644
index c152b846a0..0000000000
--- a/vendor/github.com/quic-go/quic-go/logging/generate_multiplexer.go
+++ /dev/null
@@ -1,161 +0,0 @@
-//go:build generate
-
-package main
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/parser"
- "go/printer"
- "go/token"
- "log"
- "os"
- "strings"
- "text/template"
-
- "golang.org/x/tools/imports"
-)
-
-func main() {
- if len(os.Args) != 5 {
- log.Fatalf("Usage: %s 1 && flds[1][1] == 'D',
- }
- if px.Type == Func {
- n, err := strconv.Atoi(flds[2])
- if err != nil {
- continue // should never happen
- }
- px.Results = int16(n)
- if len(flds) >= 4 {
- sig := strings.Split(flds[3], " ")
- for i := range sig {
- // $ cannot otherwise occur. removing the spaces
- // almost works, but for chan struct{}, e.g.
- sig[i] = strings.Replace(sig[i], "$", " ", -1)
- }
- px.Sig = toFields(sig)
- }
- }
- ans = append(ans, px)
- }
- }
- return ans
-}
-
-func toFields(sig []string) []Field {
- ans := make([]Field, len(sig)/2)
- for i := range ans {
- ans[i] = Field{Arg: sig[2*i], Type: sig[2*i+1]}
- }
- return ans
-}
-
-// benchmarks show this is measurably better than strings.Split
-// split into first 4 fields separated by single space
-func fastSplit(x string) []string {
- ans := make([]string, 0, 4)
- nxt := 0
- start := 0
- for i := 0; i < len(x); i++ {
- if x[i] != ' ' {
- continue
- }
- ans = append(ans, x[start:i])
- nxt++
- start = i + 1
- if nxt >= 3 {
- break
- }
- }
- ans = append(ans, x[start:])
- return ans
-}
-
-func asLexType(c byte) LexType {
- switch c {
- case 'C':
- return Const
- case 'V':
- return Var
- case 'T':
- return Type
- case 'F':
- return Func
- }
- return -1
-}
diff --git a/vendor/golang.org/x/tools/internal/modindex/modindex.go b/vendor/golang.org/x/tools/internal/modindex/modindex.go
deleted file mode 100644
index 5fa285d98e..0000000000
--- a/vendor/golang.org/x/tools/internal/modindex/modindex.go
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2024 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 modindex contains code for building and searching an
-// [Index] of the Go module cache.
-package modindex
-
-// The directory containing the index, returned by
-// [IndexDir], contains a file index-name- that contains the name
-// of the current index. We believe writing that short file is atomic.
-// [Read] reads that file to get the file name of the index.
-// WriteIndex writes an index with a unique name and then
-// writes that name into a new version of index-name-.
-// ( stands for the CurrentVersion of the index format.)
-
-import (
- "maps"
- "os"
- "path/filepath"
- "slices"
- "strings"
- "time"
-
- "golang.org/x/mod/semver"
-)
-
-// Update updates the index for the specified Go
-// module cache directory, creating it as needed.
-// On success it returns the current index.
-func Update(gomodcache string) (*Index, error) {
- prev, err := Read(gomodcache)
- if err != nil {
- if !os.IsNotExist(err) {
- return nil, err
- }
- prev = nil
- }
- return update(gomodcache, prev)
-}
-
-// update builds, writes, and returns the current index.
-//
-// If old is nil, the new index is built from all of GOMODCACHE;
-// otherwise it is built from the old index plus cache updates
-// since the previous index's time.
-func update(gomodcache string, old *Index) (*Index, error) {
- gomodcache, err := filepath.Abs(gomodcache)
- if err != nil {
- return nil, err
- }
- new, changed, err := build(gomodcache, old)
- if err != nil {
- return nil, err
- }
- if old == nil || changed {
- if err := write(gomodcache, new); err != nil {
- return nil, err
- }
- }
- return new, nil
-}
-
-// build returns a new index for the specified Go module cache (an
-// absolute path).
-//
-// If an old index is provided, only directories more recent than it
-// that it are scanned; older directories are provided by the old
-// Index.
-//
-// The boolean result indicates whether new entries were found.
-func build(gomodcache string, old *Index) (*Index, bool, error) {
- // Set the time window.
- var start time.Time // = dawn of time
- if old != nil {
- start = old.ValidAt
- }
- now := time.Now()
- end := now.Add(24 * time.Hour) // safely in the future
-
- // Enumerate GOMODCACHE package directories.
- // Choose the best (latest) package for each import path.
- pkgDirs := findDirs(gomodcache, start, end)
- dirByPath, err := bestDirByImportPath(pkgDirs)
- if err != nil {
- return nil, false, err
- }
-
- // For each import path it might occur only in
- // dirByPath, only in old, or in both.
- // If both, use the semantically later one.
- var entries []Entry
- if old != nil {
- for _, entry := range old.Entries {
- dir, ok := dirByPath[entry.ImportPath]
- if !ok || semver.Compare(dir.version, entry.Version) <= 0 {
- // New dir is missing or not more recent; use old entry.
- entries = append(entries, entry)
- delete(dirByPath, entry.ImportPath)
- }
- }
- }
-
- // Extract symbol information for all the new directories.
- newEntries := extractSymbols(gomodcache, maps.Values(dirByPath))
- entries = append(entries, newEntries...)
- slices.SortFunc(entries, func(x, y Entry) int {
- if n := strings.Compare(x.PkgName, y.PkgName); n != 0 {
- return n
- }
- return strings.Compare(x.ImportPath, y.ImportPath)
- })
-
- return &Index{
- GOMODCACHE: gomodcache,
- ValidAt: now, // time before the directories were scanned
- Entries: entries,
- }, len(newEntries) > 0, nil
-}
diff --git a/vendor/golang.org/x/tools/internal/modindex/symbols.go b/vendor/golang.org/x/tools/internal/modindex/symbols.go
deleted file mode 100644
index 8e9702d84b..0000000000
--- a/vendor/golang.org/x/tools/internal/modindex/symbols.go
+++ /dev/null
@@ -1,244 +0,0 @@
-// Copyright 2024 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 modindex
-
-import (
- "fmt"
- "go/ast"
- "go/parser"
- "go/token"
- "go/types"
- "iter"
- "os"
- "path/filepath"
- "runtime"
- "slices"
- "strings"
- "sync"
-
- "golang.org/x/sync/errgroup"
-)
-
-// The name of a symbol contains information about the symbol:
-// T for types, TD if the type is deprecated
-// C for consts, CD if the const is deprecated
-// V for vars, VD if the var is deprecated
-// and for funcs: F ( )*
-// any spaces in are replaced by $s so that the fields
-// of the name are space separated. F is replaced by FD if the func
-// is deprecated.
-type symbol struct {
- pkg string // name of the symbols's package
- name string // declared name
- kind string // T, C, V, or F, followed by D if deprecated
- sig string // signature information, for F
-}
-
-// extractSymbols returns a (new, unordered) array of Entries, one for
-// each provided package directory, describing its exported symbols.
-func extractSymbols(cwd string, dirs iter.Seq[directory]) []Entry {
- var (
- mu sync.Mutex
- entries []Entry
- )
-
- var g errgroup.Group
- g.SetLimit(max(2, runtime.GOMAXPROCS(0)/2))
- for dir := range dirs {
- g.Go(func() error {
- thedir := filepath.Join(cwd, string(dir.path))
- mode := parser.SkipObjectResolution | parser.ParseComments
-
- // Parse all Go files in dir and extract symbols.
- dirents, err := os.ReadDir(thedir)
- if err != nil {
- return nil // log this someday?
- }
- var syms []symbol
- for _, dirent := range dirents {
- if !strings.HasSuffix(dirent.Name(), ".go") ||
- strings.HasSuffix(dirent.Name(), "_test.go") {
- continue
- }
- fname := filepath.Join(thedir, dirent.Name())
- tr, err := parser.ParseFile(token.NewFileSet(), fname, nil, mode)
- if err != nil {
- continue // ignore errors, someday log them?
- }
- syms = append(syms, getFileExports(tr)...)
- }
-
- // Create an entry for the package.
- pkg, names := processSyms(syms)
- if pkg != "" {
- mu.Lock()
- defer mu.Unlock()
- entries = append(entries, Entry{
- PkgName: pkg,
- Dir: dir.path,
- ImportPath: dir.importPath,
- Version: dir.version,
- Names: names,
- })
- }
-
- return nil
- })
- }
- g.Wait() // ignore error
-
- return entries
-}
-
-func getFileExports(f *ast.File) []symbol {
- pkg := f.Name.Name
- if pkg == "main" || pkg == "" {
- return nil
- }
- var ans []symbol
- // should we look for //go:build ignore?
- for _, decl := range f.Decls {
- switch decl := decl.(type) {
- case *ast.FuncDecl:
- if decl.Recv != nil {
- // ignore methods, as we are completing package selections
- continue
- }
- name := decl.Name.Name
- dtype := decl.Type
- // not looking at dtype.TypeParams. That is, treating
- // generic functions just like non-generic ones.
- sig := dtype.Params
- kind := "F"
- if isDeprecated(decl.Doc) {
- kind += "D"
- }
- result := []string{fmt.Sprintf("%d", dtype.Results.NumFields())}
- for _, x := range sig.List {
- // This code creates a string representing the type.
- // TODO(pjw): it may be fragile:
- // 1. x.Type could be nil, perhaps in ill-formed code
- // 2. ExprString might someday change incompatibly to
- // include struct tags, which can be arbitrary strings
- if x.Type == nil {
- // Can this happen without a parse error? (Files with parse
- // errors are ignored in getSymbols)
- continue // maybe report this someday
- }
- tp := types.ExprString(x.Type)
- if len(tp) == 0 {
- // Can this happen?
- continue // maybe report this someday
- }
- // This is only safe if ExprString never returns anything with a $
- // The only place a $ can occur seems to be in a struct tag, which
- // can be an arbitrary string literal, and ExprString does not presently
- // print struct tags. So for this to happen the type of a formal parameter
- // has to be a explicit struct, e.g. foo(x struct{a int "$"}) and ExprString
- // would have to show the struct tag. Even testing for this case seems
- // a waste of effort, but let's remember the possibility
- if strings.Contains(tp, "$") {
- continue
- }
- tp = strings.Replace(tp, " ", "$", -1)
- if len(x.Names) == 0 {
- result = append(result, "_")
- result = append(result, tp)
- } else {
- for _, y := range x.Names {
- result = append(result, y.Name)
- result = append(result, tp)
- }
- }
- }
- sigs := strings.Join(result, " ")
- if s := newsym(pkg, name, kind, sigs); s != nil {
- ans = append(ans, *s)
- }
- case *ast.GenDecl:
- depr := isDeprecated(decl.Doc)
- switch decl.Tok {
- case token.CONST, token.VAR:
- tp := "V"
- if decl.Tok == token.CONST {
- tp = "C"
- }
- if depr {
- tp += "D"
- }
- for _, sp := range decl.Specs {
- for _, x := range sp.(*ast.ValueSpec).Names {
- if s := newsym(pkg, x.Name, tp, ""); s != nil {
- ans = append(ans, *s)
- }
- }
- }
- case token.TYPE:
- tp := "T"
- if depr {
- tp += "D"
- }
- for _, sp := range decl.Specs {
- if s := newsym(pkg, sp.(*ast.TypeSpec).Name.Name, tp, ""); s != nil {
- ans = append(ans, *s)
- }
- }
- }
- }
- }
- return ans
-}
-
-func newsym(pkg, name, kind, sig string) *symbol {
- if len(name) == 0 || !ast.IsExported(name) {
- return nil
- }
- sym := symbol{pkg: pkg, name: name, kind: kind, sig: sig}
- return &sym
-}
-
-func isDeprecated(doc *ast.CommentGroup) bool {
- if doc == nil {
- return false
- }
- // go.dev/wiki/Deprecated Paragraph starting 'Deprecated:'
- // This code fails for /* Deprecated: */, but it's the code from
- // gopls/internal/analysis/deprecated
- for line := range strings.SplitSeq(doc.Text(), "\n\n") {
- if strings.HasPrefix(line, "Deprecated:") {
- return true
- }
- }
- return false
-}
-
-// return the package name and the value for the symbols.
-// if there are multiple packages, choose one arbitrarily
-// the returned slice is sorted lexicographically
-func processSyms(syms []symbol) (string, []string) {
- if len(syms) == 0 {
- return "", nil
- }
- slices.SortFunc(syms, func(l, r symbol) int {
- return strings.Compare(l.name, r.name)
- })
- pkg := syms[0].pkg
- var names []string
- for _, s := range syms {
- if s.pkg != pkg {
- // Symbols came from two files in same dir
- // with different package declarations.
- continue
- }
- var nx string
- if s.sig != "" {
- nx = fmt.Sprintf("%s %s %s", s.name, s.kind, s.sig)
- } else {
- nx = fmt.Sprintf("%s %s", s.name, s.kind)
- }
- names = append(names, nx)
- }
- return pkg, names
-}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 3144c0647b..f4bd8614d5 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -681,7 +681,7 @@ github.com/prometheus/procfs/internal/util
# github.com/puzpuzpuz/xsync/v3 v3.5.1
## explicit; go 1.18
github.com/puzpuzpuz/xsync/v3
-# github.com/quic-go/quic-go v0.55.0
+# github.com/quic-go/quic-go v0.59.1
## explicit; go 1.24
github.com/quic-go/quic-go
github.com/quic-go/quic-go/internal/ackhandler
@@ -695,7 +695,9 @@ github.com/quic-go/quic-go/internal/utils
github.com/quic-go/quic-go/internal/utils/linkedlist
github.com/quic-go/quic-go/internal/utils/ringbuffer
github.com/quic-go/quic-go/internal/wire
-github.com/quic-go/quic-go/logging
+github.com/quic-go/quic-go/qlog
+github.com/quic-go/quic-go/qlogwriter
+github.com/quic-go/quic-go/qlogwriter/jsontext
github.com/quic-go/quic-go/quicvarint
# github.com/secure-systems-lab/go-securesystemslib v0.9.0
## explicit; go 1.20
@@ -889,8 +891,6 @@ golang.org/x/crypto/pkcs12/internal/rc2
golang.org/x/exp/constraints
# golang.org/x/mod v0.34.0
## explicit; go 1.25.0
-golang.org/x/mod/internal/lazyregexp
-golang.org/x/mod/module
golang.org/x/mod/semver
# golang.org/x/net v0.53.0
## explicit; go 1.25.0
@@ -946,14 +946,12 @@ golang.org/x/text/unicode/norm
golang.org/x/time/rate
# golang.org/x/tools v0.43.0
## explicit; go 1.25.0
-golang.org/x/tools/go/ast/astutil
golang.org/x/tools/go/ast/edge
golang.org/x/tools/go/ast/inspector
golang.org/x/tools/go/gcexportdata
golang.org/x/tools/go/packages
golang.org/x/tools/go/types/objectpath
golang.org/x/tools/go/types/typeutil
-golang.org/x/tools/imports
golang.org/x/tools/internal/aliases
golang.org/x/tools/internal/event
golang.org/x/tools/internal/event/core
@@ -961,9 +959,6 @@ golang.org/x/tools/internal/event/keys
golang.org/x/tools/internal/event/label
golang.org/x/tools/internal/gcimporter
golang.org/x/tools/internal/gocommand
-golang.org/x/tools/internal/gopathwalk
-golang.org/x/tools/internal/imports
-golang.org/x/tools/internal/modindex
golang.org/x/tools/internal/packagesinternal
golang.org/x/tools/internal/pkgbits
golang.org/x/tools/internal/stdlib