use the new error types to log the reason why a connection is closed

This commit is contained in:
Marten Seemann 2021-05-03 14:00:41 +07:00
parent 5f2cf0422e
commit 1613809ba2
16 changed files with 87 additions and 307 deletions

View file

@ -344,7 +344,7 @@ func (t *connTracer) StartedConnection(local, remote net.Addr, srcConnID, destCo
func (t *connTracer) NegotiatedVersion(chosen logging.VersionNumber, clientVersions, serverVersions []logging.VersionNumber) {
}
func (t *connTracer) ClosedConnection(logging.CloseReason) {}
func (t *connTracer) ClosedConnection(error) {}
func (t *connTracer) SentTransportParameters(*logging.TransportParameters) {}
func (t *connTracer) ReceivedTransportParameters(*logging.TransportParameters) {}
func (t *connTracer) RestoredTransportParameters(*logging.TransportParameters) {}

View file

@ -41,7 +41,7 @@ func (t *customConnTracer) StartedConnection(local, remote net.Addr, srcConnID,
func (t *customConnTracer) NegotiatedVersion(chosen logging.VersionNumber, clientVersions, serverVersions []logging.VersionNumber) {
}
func (t *customConnTracer) ClosedConnection(logging.CloseReason) {}
func (t *customConnTracer) ClosedConnection(error) {}
func (t *customConnTracer) SentTransportParameters(*logging.TransportParameters) {}
func (t *customConnTracer) ReceivedTransportParameters(*logging.TransportParameters) {}
func (t *customConnTracer) RestoredTransportParameters(*logging.TransportParameters) {}

View file

@ -76,7 +76,7 @@ func (mr *MockConnectionTracerMockRecorder) Close() *gomock.Call {
}
// ClosedConnection mocks base method.
func (m *MockConnectionTracer) ClosedConnection(arg0 logging.CloseReason) {
func (m *MockConnectionTracer) ClosedConnection(arg0 error) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ClosedConnection", arg0)
}

View file

@ -1,78 +0,0 @@
package logging
// A CloseReason is the reason why a QUIC connection is closed.
// It falls in one of 4 categories:
// 1. The application closed the connection (with an application-specific error code).
// 2. The transport closed the connection with a transport-error code.
// 3. The connection timed out, either during the handshake, or due to an idle timeout.
// 4. A stateless reset was received.
type CloseReason struct {
remote bool
applicationError *ApplicationError
transportError *TransportError
timeout *TimeoutReason
statelessResetToken *StatelessResetToken
versions []VersionNumber
}
// NewApplicationCloseReason creates a new CloseReason for an application error.
func NewApplicationCloseReason(errorCode ApplicationError, remote bool) CloseReason {
return CloseReason{remote: remote, applicationError: &errorCode}
}
// NewTransportCloseReason creates a new CloseReason for a transport error.
func NewTransportCloseReason(errorCode TransportError, remote bool) CloseReason {
return CloseReason{remote: remote, transportError: &errorCode}
}
// NewTimeoutCloseReason creates a new CloseReason for a connection timeout.
func NewTimeoutCloseReason(r TimeoutReason) CloseReason {
return CloseReason{timeout: &r}
}
// NewStatelessResetCloseReason creates a new CloseReason for a stateless reset.
func NewStatelessResetCloseReason(token StatelessResetToken) CloseReason {
return CloseReason{statelessResetToken: &token}
}
// NewVersionNegotiationError creates a new CloseReason for a version negotiation error.
func NewVersionNegotiationError(versions []VersionNumber) CloseReason {
return CloseReason{versions: versions}
}
// ApplicationError gets the application error.
func (r *CloseReason) ApplicationError() (errorCode ApplicationError, remote bool, ok bool) {
if r.applicationError == nil {
return
}
return *r.applicationError, r.remote, true
}
// TransportError gets the transport error.
func (r *CloseReason) TransportError() (errorCode TransportError, remote bool, ok bool) {
if r.transportError == nil {
return
}
return *r.transportError, r.remote, true
}
// Timeout gets the timeout error.
func (r *CloseReason) Timeout() (reason TimeoutReason, ok bool) {
if r.timeout == nil {
return
}
return *r.timeout, true
}
// StatelessReset gets the stateless reset token.
func (r *CloseReason) StatelessReset() (token StatelessResetToken, ok bool) {
if r.statelessResetToken == nil {
return
}
return *r.statelessResetToken, true
}
func (r *CloseReason) VersionNegotiation() (versions []VersionNumber, ok bool) {
return r.versions, len(r.versions) > 0
}

View file

@ -1,89 +0,0 @@
package logging
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Close Reason", func() {
checkNotApplicationError := func(r CloseReason) {
_, _, ok := r.ApplicationError()
Expect(ok).To(BeFalse())
}
checkNotTransportError := func(r CloseReason) {
_, _, ok := r.TransportError()
Expect(ok).To(BeFalse())
}
checkNotStatelessReset := func(r CloseReason) {
_, ok := r.StatelessReset()
ExpectWithOffset(1, ok).To(BeFalse())
}
checkNotTimeout := func(r CloseReason) {
_, ok := r.Timeout()
ExpectWithOffset(1, ok).To(BeFalse())
}
checkNotVN := func(r CloseReason) {
_, ok := r.VersionNegotiation()
ExpectWithOffset(1, ok).To(BeFalse())
}
It("application errors", func() {
r := NewApplicationCloseReason(1337, true)
errorCode, remote, ok := r.ApplicationError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeTrue())
Expect(errorCode).To(Equal(ApplicationError(1337)))
checkNotTransportError(r)
checkNotStatelessReset(r)
checkNotTimeout(r)
checkNotVN(r)
})
It("transport errors", func() {
r := NewTransportCloseReason(1337, true)
errorCode, remote, ok := r.TransportError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeTrue())
Expect(errorCode).To(Equal(TransportError(1337)))
checkNotApplicationError(r)
checkNotStatelessReset(r)
checkNotTimeout(r)
checkNotVN(r)
})
It("transport errors", func() {
r := NewTimeoutCloseReason(TimeoutReasonIdle)
timeout, ok := r.Timeout()
Expect(ok).To(BeTrue())
Expect(timeout).To(Equal(TimeoutReasonIdle))
checkNotApplicationError(r)
checkNotTransportError(r)
checkNotVN(r)
})
It("stateless resets", func() {
r := NewStatelessResetCloseReason(StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})
token, ok := r.StatelessReset()
Expect(ok).To(BeTrue())
Expect(token).To(Equal(StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}))
checkNotApplicationError(r)
checkNotTransportError(r)
checkNotTimeout(r)
checkNotVN(r)
})
It("version negotiation errors", func() {
r := NewVersionNegotiationError([]VersionNumber{1, 2, 3})
vn, ok := r.VersionNegotiation()
Expect(ok).To(BeTrue())
Expect(vn).To(Equal([]VersionNumber{1, 2, 3}))
checkNotApplicationError(r)
checkNotTransportError(r)
checkNotTimeout(r)
checkNotStatelessReset(r)
})
})

View file

@ -106,7 +106,7 @@ type Tracer interface {
type ConnectionTracer interface {
StartedConnection(local, remote net.Addr, srcConnID, destConnID ConnectionID)
NegotiatedVersion(chosen VersionNumber, clientVersions, serverVersions []VersionNumber)
ClosedConnection(CloseReason)
ClosedConnection(error)
SentTransportParameters(*TransportParameters)
ReceivedTransportParameters(*TransportParameters)
RestoredTransportParameters(parameters *TransportParameters) // for 0-RTT

View file

@ -75,7 +75,7 @@ func (mr *MockConnectionTracerMockRecorder) Close() *gomock.Call {
}
// ClosedConnection mocks base method.
func (m *MockConnectionTracer) ClosedConnection(arg0 CloseReason) {
func (m *MockConnectionTracer) ClosedConnection(arg0 error) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "ClosedConnection", arg0)
}

View file

@ -74,9 +74,9 @@ func (m *connTracerMultiplexer) NegotiatedVersion(chosen VersionNumber, clientVe
}
}
func (m *connTracerMultiplexer) ClosedConnection(reason CloseReason) {
func (m *connTracerMultiplexer) ClosedConnection(e error) {
for _, t := range m.tracers {
t.ClosedConnection(reason)
t.ClosedConnection(e)
}
}

View file

@ -2,6 +2,7 @@ package logging
import (
"context"
"errors"
"net"
"time"
@ -111,10 +112,10 @@ var _ = Describe("Tracing", func() {
})
It("traces the ClosedConnection event", func() {
reason := NewTimeoutCloseReason(TimeoutReasonIdle)
tr1.EXPECT().ClosedConnection(reason)
tr2.EXPECT().ClosedConnection(reason)
tracer.ClosedConnection(reason)
e := errors.New("test err")
tr1.EXPECT().ClosedConnection(e)
tr2.EXPECT().ClosedConnection(e)
tracer.ClosedConnection(e)
})
It("traces the SentTransportParameters event", func() {

View file

@ -1,13 +1,14 @@
package qlog
import (
"errors"
"fmt"
"net"
"time"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/logging"
"github.com/francoispqt/gojay"
@ -103,7 +104,7 @@ func (e eventVersionNegotiated) MarshalJSONObject(enc *gojay.Encoder) {
}
type eventConnectionClosed struct {
Reason logging.CloseReason
e error
}
func (e eventConnectionClosed) Category() category { return categoryTransport }
@ -111,34 +112,40 @@ func (e eventConnectionClosed) Name() string { return "connection_closed"
func (e eventConnectionClosed) IsNil() bool { return false }
func (e eventConnectionClosed) MarshalJSONObject(enc *gojay.Encoder) {
if token, ok := e.Reason.StatelessReset(); ok {
var (
statelessResetErr *quic.StatelessResetError
handshakeTimeoutErr *quic.HandshakeTimeoutError
idleTimeoutErr *quic.IdleTimeoutError
applicationErr *quic.ApplicationError
transportErr *quic.TransportError
versionNegotiationErr *quic.VersionNegotiationError
)
switch {
case errors.As(e.e, &statelessResetErr):
enc.StringKey("owner", ownerRemote.String())
enc.StringKey("trigger", "stateless_reset")
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", token))
return
}
if timeout, ok := e.Reason.Timeout(); ok {
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", statelessResetErr.Token))
case errors.As(e.e, &handshakeTimeoutErr):
enc.StringKey("owner", ownerLocal.String())
enc.StringKey("trigger", timeoutReason(timeout).String())
return
}
if code, remote, ok := e.Reason.ApplicationError(); ok {
enc.StringKey("trigger", "handshake_timeout")
case errors.As(e.e, &idleTimeoutErr):
enc.StringKey("owner", ownerLocal.String())
enc.StringKey("trigger", "idle_timeout")
case errors.As(e.e, &applicationErr):
owner := ownerLocal
if remote {
if applicationErr.Remote {
owner = ownerRemote
}
enc.StringKey("owner", owner.String())
enc.Uint64Key("application_code", uint64(code))
}
if code, remote, ok := e.Reason.TransportError(); ok {
enc.Uint64Key("application_code", uint64(applicationErr.ErrorCode))
case errors.As(e.e, &transportErr):
owner := ownerLocal
if remote {
if transportErr.Remote {
owner = ownerRemote
}
enc.StringKey("owner", owner.String())
enc.StringKey("connection_code", transportError(code).String())
}
if _, ok := e.Reason.VersionNegotiation(); ok {
enc.StringKey("connection_code", transportError(transportErr.ErrorCode).String())
case errors.As(e.e, &versionNegotiationErr):
enc.StringKey("owner", ownerRemote.String())
enc.StringKey("trigger", "version_negotiation")
}

View file

@ -206,9 +206,9 @@ func (t *connectionTracer) NegotiatedVersion(chosen logging.VersionNumber, clien
t.mutex.Unlock()
}
func (t *connectionTracer) ClosedConnection(r logging.CloseReason) {
func (t *connectionTracer) ClosedConnection(e error) {
t.mutex.Lock()
t.recordEvent(time.Now(), &eventConnectionClosed{Reason: r})
t.recordEvent(time.Now(), &eventConnectionClosed{e: e})
t.mutex.Unlock()
}

View file

@ -11,6 +11,7 @@ import (
"os"
"time"
"github.com/lucas-clemente/quic-go"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/qerr"
"github.com/lucas-clemente/quic-go/internal/utils"
@ -195,7 +196,7 @@ var _ = Describe("Tracing", func() {
})
It("records idle timeouts", func() {
tracer.ClosedConnection(logging.NewTimeoutCloseReason(logging.TimeoutReasonIdle))
tracer.ClosedConnection(&quic.IdleTimeoutError{})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond)))
Expect(entry.Name).To(Equal("transport:connection_closed"))
@ -206,7 +207,7 @@ var _ = Describe("Tracing", func() {
})
It("records handshake timeouts", func() {
tracer.ClosedConnection(logging.NewTimeoutCloseReason(logging.TimeoutReasonHandshake))
tracer.ClosedConnection(&quic.HandshakeTimeoutError{})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond)))
Expect(entry.Name).To(Equal("transport:connection_closed"))
@ -217,7 +218,9 @@ var _ = Describe("Tracing", func() {
})
It("records a received stateless reset packet", func() {
tracer.ClosedConnection(logging.NewStatelessResetCloseReason(logging.StatelessResetToken{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}))
tracer.ClosedConnection(&quic.StatelessResetError{
Token: protocol.StatelessResetToken{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond)))
Expect(entry.Name).To(Equal("transport:connection_closed"))
@ -229,7 +232,7 @@ var _ = Describe("Tracing", func() {
})
It("records connection closing due to version negotiation failure", func() {
tracer.ClosedConnection(logging.NewVersionNegotiationError([]logging.VersionNumber{1, 2, 3}))
tracer.ClosedConnection(&quic.VersionNegotiationError{})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond)))
Expect(entry.Name).To(Equal("transport:connection_closed"))
@ -240,7 +243,10 @@ var _ = Describe("Tracing", func() {
})
It("records application errors", func() {
tracer.ClosedConnection(logging.NewApplicationCloseReason(1337, true))
tracer.ClosedConnection(&quic.ApplicationError{
Remote: true,
ErrorCode: 1337,
})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond)))
Expect(entry.Name).To(Equal("transport:connection_closed"))
@ -251,7 +257,7 @@ var _ = Describe("Tracing", func() {
})
It("records transport errors", func() {
tracer.ClosedConnection(logging.NewTransportCloseReason(qerr.AEADLimitReached, false))
tracer.ClosedConnection(&quic.TransportError{ErrorCode: qerr.AEADLimitReached})
entry := exportAndParseSingle()
Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond)))
Expect(entry.Name).To(Equal("transport:connection_closed"))

View file

@ -302,19 +302,6 @@ func (t timerType) String() string {
}
}
type timeoutReason logging.TimeoutReason
func (r timeoutReason) String() string {
switch logging.TimeoutReason(r) {
case logging.TimeoutReasonHandshake:
return "handshake_timeout"
case logging.TimeoutReasonIdle:
return "idle_timeout"
default:
return "unknown close reason"
}
}
type congestionState logging.CongestionState
func (s congestionState) String() string {

View file

@ -58,11 +58,6 @@ var _ = Describe("Types", func() {
Expect(timerType(logging.TimerTypePTO).String()).To(Equal("pto"))
})
It("has a string representation for the close reason", func() {
Expect(timeoutReason(logging.TimeoutReasonHandshake).String()).To(Equal("handshake_timeout"))
Expect(timeoutReason(logging.TimeoutReasonIdle).String()).To(Equal("idle_timeout"))
})
It("has a string representation for the key type", func() {
Expect(encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveClient).String()).To(Equal("client_initial_secret"))
Expect(encLevelToKeyType(protocol.EncryptionInitial, protocol.PerspectiveServer).String()).To(Equal("server_initial_secret"))

View file

@ -1502,26 +1502,7 @@ func (s *session) handleCloseError(closeErr *closeError) {
}
if s.tracer != nil && !errors.Is(e, &errCloseForRecreating{}) {
var (
resetErr *StatelessResetError
vnErr *VersionNegotiationError
transportErr *qerr.TransportError
applicationErr *qerr.ApplicationError
)
switch {
case errors.Is(e, qerr.ErrIdleTimeout):
s.tracer.ClosedConnection(logging.NewTimeoutCloseReason(logging.TimeoutReasonIdle))
case errors.Is(e, qerr.ErrHandshakeTimeout):
s.tracer.ClosedConnection(logging.NewTimeoutCloseReason(logging.TimeoutReasonHandshake))
case errors.As(e, &resetErr):
s.tracer.ClosedConnection(logging.NewStatelessResetCloseReason(resetErr.Token))
case errors.As(e, &vnErr):
s.tracer.ClosedConnection(logging.NewVersionNegotiationError(vnErr.Theirs))
case errors.As(e, &applicationErr):
s.tracer.ClosedConnection(logging.NewApplicationCloseReason(logging.ApplicationError(applicationErr.ErrorCode), closeErr.remote))
case errors.As(e, &transportErr):
s.tracer.ClosedConnection(logging.NewTransportCloseReason(transportErr.ErrorCode, closeErr.remote))
}
s.tracer.ClosedConnection(e)
}
// If this is a remote close we're done here

View file

@ -337,12 +337,7 @@ var _ = Describe("Session", func() {
})
cryptoSetup.EXPECT().Close()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
errorCode, remote, ok := reason.TransportError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeTrue())
Expect(errorCode).To(Equal(qerr.StreamLimitError))
}),
tracer.EXPECT().ClosedConnection(expectedErr),
tracer.EXPECT().Close(),
)
@ -373,12 +368,7 @@ var _ = Describe("Session", func() {
})
cryptoSetup.EXPECT().Close()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
errorCode, remote, ok := reason.ApplicationError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeTrue())
Expect(errorCode).To(BeEquivalentTo(0x1337))
}),
tracer.EXPECT().ClosedConnection(testErr),
tracer.EXPECT().Close(),
)
@ -452,11 +442,11 @@ var _ = Describe("Session", func() {
})
mconn.EXPECT().Write([]byte("connection close"))
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
errorCode, remote, ok := reason.ApplicationError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeFalse())
Expect(errorCode).To(BeZero())
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
var appErr *ApplicationError
Expect(errors.As(e, &appErr)).To(BeTrue())
Expect(appErr.Remote).To(BeFalse())
Expect(appErr.ErrorCode).To(BeZero())
}),
tracer.EXPECT().Close(),
)
@ -492,12 +482,7 @@ var _ = Describe("Session", func() {
packer.EXPECT().PackApplicationClose(expectedErr).Return(&coalescedPacket{buffer: getPacketBuffer()}, nil)
mconn.EXPECT().Write(gomock.Any())
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
errorCode, remote, ok := reason.ApplicationError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeFalse())
Expect(errorCode).To(Equal(logging.ApplicationError(0x1337)))
}),
tracer.EXPECT().ClosedConnection(expectedErr),
tracer.EXPECT().Close(),
)
sess.CloseWithError(0x1337, "test error")
@ -518,12 +503,7 @@ var _ = Describe("Session", func() {
packer.EXPECT().PackConnectionClose(expectedErr).Return(&coalescedPacket{buffer: getPacketBuffer()}, nil)
mconn.EXPECT().Write(gomock.Any())
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
errorCode, remote, ok := reason.TransportError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeFalse())
Expect(errorCode).To(Equal(logging.TransportError(0x1337)))
}),
tracer.EXPECT().ClosedConnection(expectedErr),
tracer.EXPECT().Close(),
)
sess.closeLocal(expectedErr)
@ -539,11 +519,11 @@ var _ = Describe("Session", func() {
cryptoSetup.EXPECT().Close()
// don't EXPECT any calls to mconn.Write()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
errorCode, remote, ok := reason.TransportError()
Expect(ok).To(BeTrue())
Expect(remote).To(BeFalse())
Expect(errorCode).To(Equal(qerr.InternalError))
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
var transportErr *TransportError
Expect(errors.As(e, &transportErr)).To(BeTrue())
Expect(transportErr.Remote).To(BeFalse())
Expect(transportErr.ErrorCode).To(Equal(qerr.InternalError))
}),
tracer.EXPECT().Close(),
)
@ -648,10 +628,10 @@ var _ = Describe("Session", func() {
token := protocol.StatelessResetToken{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
runSession()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
t, ok := reason.StatelessReset()
Expect(ok).To(BeTrue())
Expect(t).To(Equal(token))
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
var srErr *StatelessResetError
Expect(errors.As(e, &srErr)).To(BeTrue())
Expect(srErr.Token).To(Equal(token))
}),
tracer.EXPECT().Close(),
)
@ -2201,10 +2181,8 @@ var _ = Describe("Session", func() {
done := make(chan struct{})
cryptoSetup.EXPECT().Close()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
timeout, ok := reason.Timeout()
Expect(ok).To(BeTrue())
Expect(timeout).To(Equal(logging.TimeoutReasonIdle))
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
Expect(errors.Is(e, &IdleTimeoutError{})).To(BeTrue())
}),
tracer.EXPECT().Close(),
)
@ -2227,10 +2205,8 @@ var _ = Describe("Session", func() {
sessionRunner.EXPECT().Remove(gomock.Any()).Times(2)
cryptoSetup.EXPECT().Close()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
timeout, ok := reason.Timeout()
Expect(ok).To(BeTrue())
Expect(timeout).To(Equal(logging.TimeoutReasonHandshake))
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
Expect(errors.Is(e, &HandshakeTimeoutError{})).To(BeTrue())
}),
tracer.EXPECT().Close(),
)
@ -2258,9 +2234,9 @@ var _ = Describe("Session", func() {
return &coalescedPacket{buffer: getPacketBuffer()}, nil
})
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
_, ok := reason.Timeout()
Expect(ok).To(BeFalse())
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
Expect(errors.Is(e, &IdleTimeoutError{})).To(BeFalse())
Expect(errors.Is(e, &HandshakeTimeoutError{})).To(BeFalse())
}),
tracer.EXPECT().Close(),
)
@ -2286,10 +2262,8 @@ var _ = Describe("Session", func() {
sessionRunner.EXPECT().Remove(gomock.Any()).AnyTimes()
cryptoSetup.EXPECT().Close()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
timeout, ok := reason.Timeout()
Expect(ok).To(BeTrue())
Expect(timeout).To(Equal(logging.TimeoutReasonIdle))
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
Expect(errors.Is(e, &IdleTimeoutError{})).To(BeTrue())
}),
tracer.EXPECT().Close(),
)
@ -2317,10 +2291,8 @@ var _ = Describe("Session", func() {
)
cryptoSetup.EXPECT().Close()
gomock.InOrder(
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(reason logging.CloseReason) {
timeout, ok := reason.Timeout()
Expect(ok).To(BeTrue())
Expect(timeout).To(Equal(logging.TimeoutReasonIdle))
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
Expect(errors.Is(e, &IdleTimeoutError{})).To(BeTrue())
}),
tracer.EXPECT().Close(),
)
@ -2665,11 +2637,12 @@ var _ = Describe("Client Session", func() {
errChan <- sess.run()
}()
sessionRunner.EXPECT().Remove(srcConnID).MaxTimes(1)
var closeReason logging.CloseReason
gomock.InOrder(
tracer.EXPECT().ReceivedVersionNegotiationPacket(gomock.Any(), gomock.Any()),
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(r logging.CloseReason) {
closeReason = r
tracer.EXPECT().ClosedConnection(gomock.Any()).Do(func(e error) {
var vnErr *VersionNegotiationError
Expect(errors.As(e, &vnErr)).To(BeTrue())
Expect(vnErr.Theirs).To(ContainElement(logging.VersionNumber(12345678)))
}),
tracer.EXPECT().Close(),
)
@ -2680,9 +2653,6 @@ var _ = Describe("Client Session", func() {
Expect(err).To(HaveOccurred())
Expect(err).ToNot(BeAssignableToTypeOf(errCloseForRecreating{}))
Expect(err.Error()).To(ContainSubstring("no compatible QUIC version found"))
vns, ok := closeReason.VersionNegotiation()
Expect(ok).To(BeTrue())
Expect(vns).To(ContainElement(logging.VersionNumber(12345678)))
})
It("ignores Version Negotiation packets that offer the current version", func() {