mirror of
https://github.com/cloudflare/cloudflared.git
synced 2026-08-07 07:14:57 +00:00
Revert "TUN-10557: Bump quic-go v0.59.1"
This reverts commit 02eb75b56d.
This commit is contained in:
+52
-52
@@ -4,85 +4,85 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/quic-go/quic-go/qlog"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
)
|
||||
|
||||
// byteCountToPromCount converts an int64 byte count to float64 used in prometheus.
|
||||
func byteCountToPromCount(count int64) float64 {
|
||||
// Helper to convert logging.ByteCount(alias for int64) to float64 used in prometheus
|
||||
func byteCountToPromCount(count logging.ByteCount) float64 {
|
||||
return float64(count)
|
||||
}
|
||||
|
||||
// durationToPromGauge converts a Duration to float64 milliseconds used in prometheus.
|
||||
// Helper to convert Duration to float64 used in prometheus
|
||||
func durationToPromGauge(duration time.Duration) float64 {
|
||||
return float64(duration.Milliseconds())
|
||||
}
|
||||
|
||||
// packetTypeString converts a qlog.PacketType to a Prometheus-safe label string.
|
||||
// The allowlist prevents unbounded cardinality if upstream adds new values.
|
||||
func packetTypeString(pt qlog.PacketType) string {
|
||||
// Helper to convert https://pkg.go.dev/github.com/quic-go/quic-go@v0.23.0/logging#PacketType into string
|
||||
func packetTypeString(pt logging.PacketType) string {
|
||||
switch pt {
|
||||
case qlog.PacketTypeInitial,
|
||||
qlog.PacketTypeHandshake,
|
||||
qlog.PacketType0RTT,
|
||||
qlog.PacketType1RTT,
|
||||
qlog.PacketTypeRetry,
|
||||
qlog.PacketTypeVersionNegotiation,
|
||||
qlog.PacketTypeStatelessReset:
|
||||
return string(pt)
|
||||
case logging.PacketTypeInitial:
|
||||
return "initial"
|
||||
case logging.PacketTypeHandshake:
|
||||
return "handshake"
|
||||
case logging.PacketTypeRetry:
|
||||
return "retry"
|
||||
case logging.PacketType0RTT:
|
||||
return "0_rtt"
|
||||
case logging.PacketTypeVersionNegotiation:
|
||||
return "version_negotiation"
|
||||
case logging.PacketType1RTT:
|
||||
return "1_rtt"
|
||||
case logging.PacketTypeStatelessReset:
|
||||
return "stateless_reset"
|
||||
case logging.PacketTypeNotDetermined:
|
||||
return "undetermined"
|
||||
default:
|
||||
return "unknown_packet_type"
|
||||
}
|
||||
}
|
||||
|
||||
// packetDropReasonString converts a qlog.PacketDropReason to a Prometheus-safe label string.
|
||||
// The allowlist passes known values through and guards against unbounded cardinality.
|
||||
func packetDropReasonString(reason qlog.PacketDropReason) string {
|
||||
// Helper to convert https://pkg.go.dev/github.com/quic-go/quic-go@v0.23.0/logging#PacketDropReason into string
|
||||
func packetDropReasonString(reason logging.PacketDropReason) string {
|
||||
switch reason {
|
||||
case qlog.PacketDropKeyUnavailable,
|
||||
qlog.PacketDropUnknownConnectionID,
|
||||
qlog.PacketDropHeaderParseError,
|
||||
qlog.PacketDropPayloadDecryptError,
|
||||
qlog.PacketDropProtocolViolation,
|
||||
qlog.PacketDropDOSPrevention,
|
||||
qlog.PacketDropUnsupportedVersion,
|
||||
qlog.PacketDropUnexpectedPacket,
|
||||
qlog.PacketDropUnexpectedSourceConnectionID,
|
||||
qlog.PacketDropUnexpectedVersion,
|
||||
qlog.PacketDropDuplicate:
|
||||
return string(reason)
|
||||
case logging.PacketDropKeyUnavailable:
|
||||
return "key_unavailable"
|
||||
case logging.PacketDropUnknownConnectionID:
|
||||
return "unknown_conn_id"
|
||||
case logging.PacketDropHeaderParseError:
|
||||
return "header_parse_err"
|
||||
case logging.PacketDropPayloadDecryptError:
|
||||
return "payload_decrypt_err"
|
||||
case logging.PacketDropProtocolViolation:
|
||||
return "protocol_violation"
|
||||
case logging.PacketDropDOSPrevention:
|
||||
return "dos_prevention"
|
||||
case logging.PacketDropUnsupportedVersion:
|
||||
return "unsupported_version"
|
||||
case logging.PacketDropUnexpectedPacket:
|
||||
return "unexpected_packet"
|
||||
case logging.PacketDropUnexpectedSourceConnectionID:
|
||||
return "unexpected_src_conn_id"
|
||||
case logging.PacketDropUnexpectedVersion:
|
||||
return "unexpected_version"
|
||||
case logging.PacketDropDuplicate:
|
||||
return "duplicate"
|
||||
default:
|
||||
return "unknown_reason"
|
||||
}
|
||||
}
|
||||
|
||||
// packetLossReasonString converts a qlog.PacketLossReason to a Prometheus-safe label string.
|
||||
func packetLossReasonString(reason qlog.PacketLossReason) string {
|
||||
// Helper to convert https://pkg.go.dev/github.com/quic-go/quic-go@v0.23.0/logging#PacketLossReason into string
|
||||
func packetLossReasonString(reason logging.PacketLossReason) string {
|
||||
switch reason {
|
||||
case qlog.PacketLossReorderingThreshold,
|
||||
qlog.PacketLossTimeThreshold:
|
||||
return string(reason)
|
||||
case logging.PacketLossReorderingThreshold:
|
||||
return "reordering"
|
||||
case logging.PacketLossTimeThreshold:
|
||||
return "timeout"
|
||||
default:
|
||||
return "unknown_loss_reason"
|
||||
}
|
||||
}
|
||||
|
||||
// congestionStateToFloat maps a qlog.CongestionState string to a numeric value for prometheus gauges.
|
||||
// Mapping: slow_start=0, congestion_avoidance=1, application_limited=2, recovery=3, unknown=-1.
|
||||
func congestionStateToFloat(state qlog.CongestionState) float64 {
|
||||
switch state {
|
||||
case qlog.CongestionStateSlowStart:
|
||||
return 0
|
||||
case qlog.CongestionStateCongestionAvoidance:
|
||||
return 1
|
||||
case qlog.CongestionStateApplicationLimited:
|
||||
return 2
|
||||
case qlog.CongestionStateRecovery:
|
||||
return 3
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
}
|
||||
|
||||
func uint8ToString(input uint8) string {
|
||||
return strconv.FormatUint(uint64(input), 10)
|
||||
}
|
||||
|
||||
+3
-2
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/quic-go/quic-go"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"github.com/cloudflare/cloudflared/packet"
|
||||
@@ -24,12 +25,12 @@ type BaseDatagramMuxer interface {
|
||||
}
|
||||
|
||||
type DatagramMuxer struct {
|
||||
session QUICConnection
|
||||
session quic.Connection
|
||||
logger *zerolog.Logger
|
||||
demuxChan chan<- *packet.Session
|
||||
}
|
||||
|
||||
func NewDatagramMuxer(quicSession QUICConnection, log *zerolog.Logger, demuxChan chan<- *packet.Session) *DatagramMuxer {
|
||||
func NewDatagramMuxer(quicSession quic.Connection, log *zerolog.Logger, demuxChan chan<- *packet.Session) *DatagramMuxer {
|
||||
logger := log.With().Uint8("datagramVersion", 1).Logger()
|
||||
return &DatagramMuxer{
|
||||
session: quicSession,
|
||||
|
||||
+2
-2
@@ -141,7 +141,7 @@ func (dm *DatagramMuxerV2) demux(ctx context.Context, msgWithType []byte) error
|
||||
}
|
||||
msgType := DatagramV2Type(msgWithType[len(msgWithType)-typeIDLen])
|
||||
msg := msgWithType[0 : len(msgWithType)-typeIDLen]
|
||||
switch msgType { //nolint:exhaustive // default handles all non-UDP types via handlePacket
|
||||
switch msgType {
|
||||
case DatagramTypeUDP:
|
||||
return dm.handleSession(ctx, msg)
|
||||
case DatagramTypeIP, DatagramTypeIPWithTrace, DatagramTypeTracingSpan:
|
||||
@@ -170,7 +170,7 @@ func (dm *DatagramMuxerV2) handleSession(ctx context.Context, session []byte) er
|
||||
|
||||
func (dm *DatagramMuxerV2) handlePacket(ctx context.Context, pk []byte, msgType DatagramV2Type) error {
|
||||
var demuxedPacket Packet
|
||||
switch msgType { //nolint:exhaustive // DatagramTypeUDP is handled by the caller (demux)
|
||||
switch msgType {
|
||||
case DatagramTypeIP:
|
||||
demuxedPacket = RawPacket(packet.RawPacket{Data: pk})
|
||||
case DatagramTypeIPWithTrace:
|
||||
|
||||
+29
-50
@@ -4,10 +4,9 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/quic-go/quic-go/qlog"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
@@ -176,7 +175,7 @@ var (
|
||||
Namespace: namespace,
|
||||
Subsystem: "client",
|
||||
Name: "congestion_state",
|
||||
Help: "Current congestion control state (0=slow_start, 1=congestion_avoidance, 2=application_limited, 3=recovery, -1=unknown)",
|
||||
Help: "Current congestion control state. See https://pkg.go.dev/github.com/quic-go/quic-go@v0.45.0/logging#CongestionState for what each value maps to",
|
||||
},
|
||||
[]string{ConnectionIndexMetricLabel},
|
||||
),
|
||||
@@ -230,37 +229,28 @@ func (cc *clientCollector) startedConnection() {
|
||||
clientMetrics.totalConnections.Inc()
|
||||
}
|
||||
|
||||
func (cc *clientCollector) closedConnection() {
|
||||
func (cc *clientCollector) closedConnection(error) {
|
||||
clientMetrics.closedConnections.Inc()
|
||||
}
|
||||
|
||||
// receivedTransportParameters records metrics from the peer's transport parameters.
|
||||
func (cc *clientCollector) receivedTransportParameters(maxUDPPayloadSize int64, maxIdleTimeout time.Duration, maxDatagramFrameSize int64) {
|
||||
clientMetrics.maxUDPPayloadSize.WithLabelValues(cc.index).Set(float64(maxUDPPayloadSize))
|
||||
cc.logger.
|
||||
Debug().
|
||||
Int64("MaxUDPPayloadSize", maxUDPPayloadSize).
|
||||
Dur("MaxIdleTimeout", maxIdleTimeout).
|
||||
Int64("MaxDatagramFrameSize", maxDatagramFrameSize).Msgf("Received transport parameters")
|
||||
func (cc *clientCollector) receivedTransportParameters(params *logging.TransportParameters) {
|
||||
clientMetrics.maxUDPPayloadSize.WithLabelValues(cc.index).Set(float64(params.MaxUDPPayloadSize))
|
||||
cc.logger.Debug().Msgf("Received transport parameters: MaxUDPPayloadSize=%d, MaxIdleTimeout=%v, MaxDatagramFrameSize=%d", params.MaxUDPPayloadSize, params.MaxIdleTimeout, params.MaxDatagramFrameSize)
|
||||
}
|
||||
|
||||
// sentPackets records metrics for sent packets.
|
||||
func (cc *clientCollector) sentPackets(size int64, frames []qlog.Frame) {
|
||||
func (cc *clientCollector) sentPackets(size logging.ByteCount, frames []logging.Frame) {
|
||||
cc.collectPackets(size, frames, clientMetrics.sentFrames, clientMetrics.sentBytes, sent)
|
||||
}
|
||||
|
||||
// receivedPackets records metrics for received packets.
|
||||
func (cc *clientCollector) receivedPackets(size int64, frames []qlog.Frame) {
|
||||
func (cc *clientCollector) receivedPackets(size logging.ByteCount, frames []logging.Frame) {
|
||||
cc.collectPackets(size, frames, clientMetrics.receivedFrames, clientMetrics.receivedBytes, received)
|
||||
}
|
||||
|
||||
// bufferedPackets records metrics for buffered packets.
|
||||
func (cc *clientCollector) bufferedPackets(packetType qlog.PacketType) {
|
||||
func (cc *clientCollector) bufferedPackets(packetType logging.PacketType) {
|
||||
clientMetrics.bufferedPackets.WithLabelValues(cc.index, packetTypeString(packetType)).Inc()
|
||||
}
|
||||
|
||||
// droppedPackets records metrics for dropped packets.
|
||||
func (cc *clientCollector) droppedPackets(packetType qlog.PacketType, size int64, reason qlog.PacketDropReason) {
|
||||
func (cc *clientCollector) droppedPackets(packetType logging.PacketType, size logging.ByteCount, reason logging.PacketDropReason) {
|
||||
clientMetrics.droppedPackets.WithLabelValues(
|
||||
cc.index,
|
||||
packetTypeString(packetType),
|
||||
@@ -268,43 +258,35 @@ func (cc *clientCollector) droppedPackets(packetType qlog.PacketType, size int64
|
||||
).Add(byteCountToPromCount(size))
|
||||
}
|
||||
|
||||
// lostPackets records metrics for lost packets.
|
||||
func (cc *clientCollector) lostPackets(reason qlog.PacketLossReason) {
|
||||
func (cc *clientCollector) lostPackets(reason logging.PacketLossReason) {
|
||||
clientMetrics.lostPackets.WithLabelValues(cc.index, packetLossReasonString(reason)).Inc()
|
||||
}
|
||||
|
||||
// updatedRTT records RTT metrics.
|
||||
func (cc *clientCollector) updatedRTT(m qlog.MetricsUpdated) {
|
||||
clientMetrics.minRTT.WithLabelValues(cc.index).Set(durationToPromGauge(m.MinRTT))
|
||||
clientMetrics.latestRTT.WithLabelValues(cc.index).Set(durationToPromGauge(m.LatestRTT))
|
||||
clientMetrics.smoothedRTT.WithLabelValues(cc.index).Set(durationToPromGauge(m.SmoothedRTT))
|
||||
func (cc *clientCollector) updatedRTT(rtt *logging.RTTStats) {
|
||||
clientMetrics.minRTT.WithLabelValues(cc.index).Set(durationToPromGauge(rtt.MinRTT()))
|
||||
clientMetrics.latestRTT.WithLabelValues(cc.index).Set(durationToPromGauge(rtt.LatestRTT()))
|
||||
clientMetrics.smoothedRTT.WithLabelValues(cc.index).Set(durationToPromGauge(rtt.SmoothedRTT()))
|
||||
}
|
||||
|
||||
// updateCongestionWindow records the congestion window size.
|
||||
func (cc *clientCollector) updateCongestionWindow(size int64) {
|
||||
func (cc *clientCollector) updateCongestionWindow(size logging.ByteCount) {
|
||||
clientMetrics.congestionWindow.WithLabelValues(cc.index).Set(float64(size))
|
||||
}
|
||||
|
||||
// updatedCongestionState records the congestion control state.
|
||||
func (cc *clientCollector) updatedCongestionState(state qlog.CongestionState) {
|
||||
clientMetrics.congestionState.WithLabelValues(cc.index).Set(congestionStateToFloat(state))
|
||||
func (cc *clientCollector) updatedCongestionState(state logging.CongestionState) {
|
||||
clientMetrics.congestionState.WithLabelValues(cc.index).Set(float64(state))
|
||||
}
|
||||
|
||||
// updateMTU records the MTU value.
|
||||
func (cc *clientCollector) updateMTU(mtu int64) {
|
||||
func (cc *clientCollector) updateMTU(mtu logging.ByteCount) {
|
||||
clientMetrics.mtu.WithLabelValues(cc.index).Set(float64(mtu))
|
||||
cc.logger.Debug().Msgf("QUIC MTU updated to %d", mtu)
|
||||
}
|
||||
|
||||
// collectPackets is the shared implementation for sentPackets and receivedPackets.
|
||||
func (cc *clientCollector) collectPackets(size int64, frames []qlog.Frame, counter, bandwidth *prometheus.CounterVec, direction direction) {
|
||||
func (cc *clientCollector) collectPackets(size logging.ByteCount, frames []logging.Frame, counter, bandwidth *prometheus.CounterVec, direction direction) {
|
||||
for _, frame := range frames {
|
||||
// qlog.Frame.Frame holds the concrete wire frame type as any.
|
||||
// The quic-go encoder always stores pointers (*wire.XxxFrame).
|
||||
switch f := frame.Frame.(type) {
|
||||
case *qlog.DataBlockedFrame:
|
||||
cc.logger.Debug().Int64("limit", int64(f.MaximumData)).Msgf("%s data_blocked frame", direction)
|
||||
case *qlog.StreamDataBlockedFrame:
|
||||
switch f := frame.(type) {
|
||||
case logging.DataBlockedFrame:
|
||||
cc.logger.Debug().Msgf("%s data_blocked frame", direction)
|
||||
case logging.StreamDataBlockedFrame:
|
||||
cc.logger.Debug().Int64("streamID", int64(f.StreamID)).Msgf("%s stream_data_blocked frame", direction)
|
||||
}
|
||||
counter.WithLabelValues(cc.index, frameName(frame)).Inc()
|
||||
@@ -312,16 +294,13 @@ func (cc *clientCollector) collectPackets(size int64, frames []qlog.Frame, count
|
||||
bandwidth.WithLabelValues(cc.index).Add(byteCountToPromCount(size))
|
||||
}
|
||||
|
||||
// frameName extracts the type name from a qlog.Frame for use as a Prometheus label.
|
||||
func frameName(frame qlog.Frame) string {
|
||||
if frame.Frame == nil {
|
||||
func frameName(frame logging.Frame) string {
|
||||
if frame == nil {
|
||||
return "nil"
|
||||
} else {
|
||||
name := reflect.TypeOf(frame).Elem().Name()
|
||||
return strings.TrimSuffix(name, "Frame")
|
||||
}
|
||||
t := reflect.TypeOf(frame.Frame)
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
return strings.TrimSuffix(t.Name(), "Frame")
|
||||
}
|
||||
|
||||
type direction uint8
|
||||
|
||||
+12
-11
@@ -12,9 +12,9 @@ import (
|
||||
// QUICConnection defines the subset of [quic.Connection] methods used by cloudflared.
|
||||
// Consumers should accept this interface; producers should return [*ConnWithCloser].
|
||||
type QUICConnection interface {
|
||||
AcceptStream(ctx context.Context) (*quic.Stream, error)
|
||||
OpenStream() (*quic.Stream, error)
|
||||
OpenStreamSync(ctx context.Context) (*quic.Stream, error)
|
||||
AcceptStream(ctx context.Context) (quic.Stream, error)
|
||||
OpenStream() (quic.Stream, error)
|
||||
OpenStreamSync(ctx context.Context) (quic.Stream, error)
|
||||
CloseWithError(code quic.ApplicationErrorCode, reason string) error
|
||||
Context() context.Context
|
||||
SendDatagram(payload []byte) error
|
||||
@@ -28,9 +28,9 @@ type QUICConnection interface {
|
||||
var _ QUICConnection = (*ConnWithCloser)(nil)
|
||||
|
||||
var (
|
||||
// error returned when the [NewQUICConnection] is called with a nil conn argument
|
||||
// error returned when the [NewConnWithCloser] is called with a nil conn argument
|
||||
ErrNilQuicConnection = errors.New("the provided quic connection is nil")
|
||||
// error returned when the [NewQUICConnection] is called with a nil closer argument
|
||||
// error returned when the [NewConnWithCloser] is called with a nil closer argument
|
||||
ErrNilCloser = errors.New("the provided closer is nil")
|
||||
)
|
||||
|
||||
@@ -38,15 +38,16 @@ var (
|
||||
// underlying [*net.UDPConn]). When [CloseWithError] is called the QUIC
|
||||
// connection is closed first, then the closer is closed deterministically.
|
||||
//
|
||||
// All fields are non-nil after successful construction via [NewQUICConnection].
|
||||
// A nil conn is only safe for [CloseWithError] (used in tests). All other
|
||||
// delegated methods will panic on a nil conn.
|
||||
type ConnWithCloser struct {
|
||||
conn *quic.Conn
|
||||
conn quic.Connection
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
// NewQUICConnection returns a [*ConnWithCloser] that will close closer after
|
||||
// the QUIC connection is closed.
|
||||
func NewQUICConnection(conn *quic.Conn, closer io.Closer) (*ConnWithCloser, error) {
|
||||
func NewQUICConnection(conn quic.Connection, closer io.Closer) (*ConnWithCloser, error) {
|
||||
if conn == nil {
|
||||
return nil, ErrNilQuicConnection
|
||||
}
|
||||
@@ -67,15 +68,15 @@ func (c *ConnWithCloser) CloseWithError(code quic.ApplicationErrorCode, reason s
|
||||
return errors.Join(connErr, closerErr)
|
||||
}
|
||||
|
||||
func (c *ConnWithCloser) AcceptStream(ctx context.Context) (*quic.Stream, error) {
|
||||
func (c *ConnWithCloser) AcceptStream(ctx context.Context) (quic.Stream, error) {
|
||||
return c.conn.AcceptStream(ctx)
|
||||
}
|
||||
|
||||
func (c *ConnWithCloser) OpenStream() (*quic.Stream, error) {
|
||||
func (c *ConnWithCloser) OpenStream() (quic.Stream, error) {
|
||||
return c.conn.OpenStream()
|
||||
}
|
||||
|
||||
func (c *ConnWithCloser) OpenStreamSync(ctx context.Context) (*quic.Stream, error) {
|
||||
func (c *ConnWithCloser) OpenStreamSync(ctx context.Context) (quic.Stream, error) {
|
||||
return c.conn.OpenStreamSync(ctx)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package quic
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/quic-go/quic-go"
|
||||
@@ -16,6 +17,16 @@ func (m *mockCloser) Close() error {
|
||||
return m.closeErr
|
||||
}
|
||||
|
||||
// mockQuicConnection is a minimal test double for [quic.Connection].
|
||||
type mockQuicConnection struct {
|
||||
quic.Connection
|
||||
closeWithErrorErr error
|
||||
}
|
||||
|
||||
func (m *mockQuicConnection) CloseWithError(_ quic.ApplicationErrorCode, _ string) error {
|
||||
return m.closeWithErrorErr
|
||||
}
|
||||
|
||||
func TestNewConnWithCloser_NilConn(t *testing.T) {
|
||||
t.Parallel()
|
||||
conn, err := NewQUICConnection(nil, &mockCloser{})
|
||||
@@ -25,7 +36,73 @@ func TestNewConnWithCloser_NilConn(t *testing.T) {
|
||||
|
||||
func TestNewConnWithCloser_NilCloser(t *testing.T) {
|
||||
t.Parallel()
|
||||
conn, err := NewQUICConnection(&quic.Conn{}, nil)
|
||||
conn, err := NewQUICConnection(&mockQuicConnection{}, nil)
|
||||
require.ErrorIs(t, err, ErrNilCloser)
|
||||
require.Nil(t, conn)
|
||||
}
|
||||
|
||||
func TestNewConnWithCloser_Success(t *testing.T) {
|
||||
t.Parallel()
|
||||
qc := &mockQuicConnection{}
|
||||
cl := &mockCloser{}
|
||||
conn, err := NewQUICConnection(qc, cl)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, conn)
|
||||
}
|
||||
|
||||
func TestConnWithCloser_CloseWithError_BothSucceed(t *testing.T) {
|
||||
t.Parallel()
|
||||
qc := &mockQuicConnection{}
|
||||
cl := &mockCloser{}
|
||||
conn, err := NewQUICConnection(qc, cl)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = conn.CloseWithError(0, "test")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestConnWithCloser_CloseWithError_QuicFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
quicErr := errors.New("quic close failed")
|
||||
qc := &mockQuicConnection{closeWithErrorErr: quicErr}
|
||||
cl := &mockCloser{}
|
||||
conn, err := NewQUICConnection(qc, cl)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = conn.CloseWithError(0, "test")
|
||||
require.ErrorIs(t, err, quicErr)
|
||||
}
|
||||
|
||||
func TestConnWithCloser_CloseWithError_CloserFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
closerErr := errors.New("closer failed")
|
||||
qc := &mockQuicConnection{}
|
||||
cl := &mockCloser{closeErr: closerErr}
|
||||
conn, err := NewQUICConnection(qc, cl)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = conn.CloseWithError(0, "test")
|
||||
require.ErrorIs(t, err, closerErr)
|
||||
}
|
||||
|
||||
func TestConnWithCloser_CloseWithError_BothFail(t *testing.T) {
|
||||
t.Parallel()
|
||||
quicErr := errors.New("quic close failed")
|
||||
closerErr := errors.New("closer failed")
|
||||
qc := &mockQuicConnection{closeWithErrorErr: quicErr}
|
||||
cl := &mockCloser{closeErr: closerErr}
|
||||
conn, err := NewQUICConnection(qc, cl)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = conn.CloseWithError(0, "test")
|
||||
require.ErrorIs(t, err, quicErr)
|
||||
require.ErrorIs(t, err, closerErr)
|
||||
}
|
||||
|
||||
// TestConnWithCloser_ImplementsInterface is a runtime assertion that
|
||||
// *ConnWithCloser satisfies QUICConnection. The compile-time assertion is in
|
||||
// quic_connection.go.
|
||||
func TestConnWithCloser_ImplementsInterface(t *testing.T) {
|
||||
t.Parallel()
|
||||
var _ QUICConnection = (*ConnWithCloser)(nil)
|
||||
}
|
||||
|
||||
+2
-2
@@ -17,13 +17,13 @@ var idleTimeoutError = quic.IdleTimeoutError{}
|
||||
|
||||
type SafeStreamCloser struct {
|
||||
lock sync.Mutex
|
||||
stream *quic.Stream
|
||||
stream quic.Stream
|
||||
writeTimeout time.Duration
|
||||
log *zerolog.Logger
|
||||
closing atomic.Bool
|
||||
}
|
||||
|
||||
func NewSafeStreamCloser(stream *quic.Stream, writeTimeout time.Duration, log *zerolog.Logger) *SafeStreamCloser {
|
||||
func NewSafeStreamCloser(stream quic.Stream, writeTimeout time.Duration, log *zerolog.Logger) *SafeStreamCloser {
|
||||
return &SafeStreamCloser{
|
||||
stream: stream,
|
||||
writeTimeout: writeTimeout,
|
||||
|
||||
+51
-78
@@ -2,20 +2,19 @@ package quic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
"net"
|
||||
|
||||
"github.com/quic-go/quic-go/qlog"
|
||||
"github.com/quic-go/quic-go/qlogwriter"
|
||||
"github.com/quic-go/quic-go/logging"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// tracer builds a connTracer for each new QUIC connection.
|
||||
// QUICTracer is a wrapper to create new quicConnTracer
|
||||
type tracer struct {
|
||||
index string
|
||||
logger *zerolog.Logger
|
||||
}
|
||||
|
||||
func NewClientTracer(logger *zerolog.Logger, index uint8) func(context.Context, bool, qlog.ConnectionID) qlogwriter.Trace {
|
||||
func NewClientTracer(logger *zerolog.Logger, index uint8) func(context.Context, logging.Perspective, logging.ConnectionID) *logging.ConnectionTracer {
|
||||
t := &tracer{
|
||||
index: uint8ToString(index),
|
||||
logger: logger,
|
||||
@@ -23,111 +22,85 @@ func NewClientTracer(logger *zerolog.Logger, index uint8) func(context.Context,
|
||||
return t.TracerForConnection
|
||||
}
|
||||
|
||||
// TracerForConnection returns a qlogwriter.Trace for a new connection.
|
||||
func (t *tracer) TracerForConnection(_ context.Context, _ bool, _ qlog.ConnectionID) qlogwriter.Trace {
|
||||
func (t *tracer) TracerForConnection(_ctx context.Context, _p logging.Perspective, _odcid logging.ConnectionID) *logging.ConnectionTracer {
|
||||
return newConnTracer(newClientCollector(t.index, t.logger))
|
||||
}
|
||||
|
||||
// connTracer collects connection level metrics. It implements
|
||||
// qlogwriter.Trace + qlogwriter.Recorder and dispatches qlog events to the
|
||||
// metric-collection methods via RecordEvent.
|
||||
// connTracer collects connection level metrics
|
||||
type connTracer struct {
|
||||
metricsCollector *clientCollector
|
||||
}
|
||||
|
||||
func newConnTracer(metricsCollector *clientCollector) *connTracer {
|
||||
return &connTracer{
|
||||
func newConnTracer(metricsCollector *clientCollector) *logging.ConnectionTracer {
|
||||
tracer := connTracer{
|
||||
metricsCollector: metricsCollector,
|
||||
}
|
||||
}
|
||||
|
||||
func (ct *connTracer) AddProducer() qlogwriter.Recorder {
|
||||
// connTracer is both the Trace and the Recorder: each connection gets
|
||||
// exactly one producer that routes events to the collector methods below.
|
||||
return ct
|
||||
}
|
||||
|
||||
func (ct *connTracer) SupportsSchemas(_ string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// RecordEvent dispatches qlog events to the collector methods.
|
||||
func (ct *connTracer) RecordEvent(ev qlogwriter.Event) {
|
||||
switch e := ev.(type) {
|
||||
case qlog.StartedConnection:
|
||||
ct.StartedConnection()
|
||||
case qlog.ConnectionClosed:
|
||||
ct.ClosedConnection()
|
||||
case qlog.ParametersSet:
|
||||
// ParametersSet fires for both local and remote; filter to remote only
|
||||
// via the Initiator field.
|
||||
if e.Initiator == qlog.InitiatorRemote {
|
||||
ct.ReceivedTransportParameters(int64(e.MaxUDPPayloadSize), e.MaxIdleTimeout, int64(e.MaxDatagramFrameSize))
|
||||
}
|
||||
case qlog.PacketSent:
|
||||
ct.SentPacket(int64(e.Raw.Length), e.Frames)
|
||||
case qlog.PacketReceived:
|
||||
ct.ReceivedPacket(int64(e.Raw.Length), e.Frames)
|
||||
case qlog.PacketBuffered:
|
||||
ct.BufferedPacket(e.Header.PacketType)
|
||||
case qlog.PacketDropped:
|
||||
ct.DroppedPacket(e.Header.PacketType, int64(e.Raw.Length), e.Trigger)
|
||||
case qlog.PacketLost:
|
||||
ct.LostPacket(e.Trigger)
|
||||
case qlog.MetricsUpdated:
|
||||
ct.UpdatedMetrics(e)
|
||||
case qlog.MTUUpdated:
|
||||
ct.UpdatedMTU(int64(e.Value))
|
||||
case qlog.CongestionStateUpdated:
|
||||
ct.UpdatedCongestionState(e.State)
|
||||
return &logging.ConnectionTracer{
|
||||
StartedConnection: tracer.StartedConnection,
|
||||
ClosedConnection: tracer.ClosedConnection,
|
||||
ReceivedTransportParameters: tracer.ReceivedTransportParameters,
|
||||
SentLongHeaderPacket: tracer.SentLongHeaderPacket,
|
||||
SentShortHeaderPacket: tracer.SentShortHeaderPacket,
|
||||
ReceivedLongHeaderPacket: tracer.ReceivedLongHeaderPacket,
|
||||
ReceivedShortHeaderPacket: tracer.ReceivedShortHeaderPacket,
|
||||
BufferedPacket: tracer.BufferedPacket,
|
||||
DroppedPacket: tracer.DroppedPacket,
|
||||
UpdatedMetrics: tracer.UpdatedMetrics,
|
||||
LostPacket: tracer.LostPacket,
|
||||
UpdatedMTU: tracer.UpdatedMTU,
|
||||
UpdatedCongestionState: tracer.UpdatedCongestionState,
|
||||
}
|
||||
}
|
||||
|
||||
func (ct *connTracer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ct *connTracer) StartedConnection() {
|
||||
func (ct *connTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID logging.ConnectionID) {
|
||||
ct.metricsCollector.startedConnection()
|
||||
}
|
||||
|
||||
func (ct *connTracer) ClosedConnection() {
|
||||
ct.metricsCollector.closedConnection()
|
||||
func (ct *connTracer) ClosedConnection(err error) {
|
||||
ct.metricsCollector.closedConnection(err)
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedTransportParameters(maxUDPPayloadSize int64, maxIdleTimeout time.Duration, maxDatagramFrameSize int64) {
|
||||
ct.metricsCollector.receivedTransportParameters(maxUDPPayloadSize, maxIdleTimeout, maxDatagramFrameSize)
|
||||
func (ct *connTracer) ReceivedTransportParameters(params *logging.TransportParameters) {
|
||||
ct.metricsCollector.receivedTransportParameters(params)
|
||||
}
|
||||
|
||||
func (ct *connTracer) SentPacket(size int64, frames []qlog.Frame) {
|
||||
ct.metricsCollector.sentPackets(size, frames)
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedPacket(size int64, frames []qlog.Frame) {
|
||||
ct.metricsCollector.receivedPackets(size, frames)
|
||||
}
|
||||
|
||||
func (ct *connTracer) BufferedPacket(pt qlog.PacketType) {
|
||||
func (ct *connTracer) BufferedPacket(pt logging.PacketType, size logging.ByteCount) {
|
||||
ct.metricsCollector.bufferedPackets(pt)
|
||||
}
|
||||
|
||||
func (ct *connTracer) DroppedPacket(pt qlog.PacketType, size int64, reason qlog.PacketDropReason) {
|
||||
func (ct *connTracer) DroppedPacket(pt logging.PacketType, number logging.PacketNumber, size logging.ByteCount, reason logging.PacketDropReason) {
|
||||
ct.metricsCollector.droppedPackets(pt, size, reason)
|
||||
}
|
||||
|
||||
func (ct *connTracer) LostPacket(reason qlog.PacketLossReason) {
|
||||
func (ct *connTracer) LostPacket(level logging.EncryptionLevel, number logging.PacketNumber, reason logging.PacketLossReason) {
|
||||
ct.metricsCollector.lostPackets(reason)
|
||||
}
|
||||
|
||||
func (ct *connTracer) UpdatedMetrics(m qlog.MetricsUpdated) {
|
||||
ct.metricsCollector.updatedRTT(m)
|
||||
ct.metricsCollector.updateCongestionWindow(int64(m.CongestionWindow))
|
||||
func (ct *connTracer) UpdatedMetrics(rttStats *logging.RTTStats, cwnd, bytesInFlight logging.ByteCount, packetsInFlight int) {
|
||||
ct.metricsCollector.updatedRTT(rttStats)
|
||||
ct.metricsCollector.updateCongestionWindow(cwnd)
|
||||
}
|
||||
|
||||
func (ct *connTracer) UpdatedMTU(mtu int64) {
|
||||
func (ct *connTracer) SentLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
|
||||
ct.metricsCollector.sentPackets(size, frames)
|
||||
}
|
||||
|
||||
func (ct *connTracer) SentShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
|
||||
ct.metricsCollector.sentPackets(size, frames)
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
|
||||
ct.metricsCollector.receivedPackets(size, frames)
|
||||
}
|
||||
|
||||
func (ct *connTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
|
||||
ct.metricsCollector.receivedPackets(size, frames)
|
||||
}
|
||||
|
||||
func (ct *connTracer) UpdatedMTU(mtu logging.ByteCount, done bool) {
|
||||
ct.metricsCollector.updateMTU(mtu)
|
||||
}
|
||||
|
||||
func (ct *connTracer) UpdatedCongestionState(state qlog.CongestionState) {
|
||||
func (ct *connTracer) UpdatedCongestionState(state logging.CongestionState) {
|
||||
ct.metricsCollector.updatedCongestionState(state)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user