From 1ce572228b9815d5bf053841725aded35d1ac530 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Sun, 25 Apr 2021 19:03:34 +0700 Subject: [PATCH] expose a VersionNegoationError --- errors.go | 12 +++++++++--- integrationtests/self/mitm_test.go | 2 +- internal/qerr/quic_error.go | 17 +++++++++++++++++ internal/qerr/quic_error_test.go | 14 ++++++++++++++ session.go | 26 ++++++-------------------- 5 files changed, 47 insertions(+), 24 deletions(-) diff --git a/errors.go b/errors.go index 0145c8dd..faa6bd6b 100644 --- a/errors.go +++ b/errors.go @@ -1,10 +1,16 @@ package quic -import "github.com/lucas-clemente/quic-go/internal/qerr" +import ( + "github.com/lucas-clemente/quic-go/internal/qerr" +) + +type ( + TransportError = qerr.TransportError + ApplicationError = qerr.ApplicationError + VersionNegotiationError = qerr.VersionNegotiationError +) type ( - TransportError = qerr.TransportError - ApplicationError = qerr.ApplicationError TransportErrorCode = qerr.TransportErrorCode ApplicationErrorCode = qerr.ApplicationErrorCode ) diff --git a/integrationtests/self/mitm_test.go b/integrationtests/self/mitm_test.go index 16a5cec4..ebd57df9 100644 --- a/integrationtests/self/mitm_test.go +++ b/integrationtests/self/mitm_test.go @@ -371,7 +371,7 @@ var _ = Describe("MITM test", func() { } err := runTest(delayCb) Expect(err).To(HaveOccurred()) - Expect(err.Error()).To(ContainSubstring("no compatible QUIC version found")) + Expect(err).To(MatchError(&quic.VersionNegotiationError{})) }) // times out, because client doesn't accept subsequent real retry packets from server diff --git a/internal/qerr/quic_error.go b/internal/qerr/quic_error.go index dadd45c9..f2739c5b 100644 --- a/internal/qerr/quic_error.go +++ b/internal/qerr/quic_error.go @@ -2,6 +2,8 @@ package qerr import ( "fmt" + + "github.com/lucas-clemente/quic-go/internal/protocol" ) var ( @@ -92,3 +94,18 @@ func (e *HandshakeTimeoutError) Is(target error) bool { _, ok := target.(*HandshakeTimeoutError) return ok } + +// A VersionNegotiationError occurs when the client and the server can't agree on a QUIC version. +type VersionNegotiationError struct { + Ours []protocol.VersionNumber + Theirs []protocol.VersionNumber +} + +func (e *VersionNegotiationError) Error() string { + return fmt.Sprintf("no compatible QUIC version found (we support %s, server offered %s)", e.Ours, e.Theirs) +} + +func (e *VersionNegotiationError) Is(target error) bool { + _, ok := target.(*VersionNegotiationError) + return ok +} diff --git a/internal/qerr/quic_error_test.go b/internal/qerr/quic_error_test.go index 362e0edf..48720e6f 100644 --- a/internal/qerr/quic_error_test.go +++ b/internal/qerr/quic_error_test.go @@ -4,6 +4,7 @@ import ( "errors" "net" + "github.com/lucas-clemente/quic-go/internal/protocol" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) @@ -101,4 +102,17 @@ var _ = Describe("QUIC Errors", func() { Expect(errors.Is(err, &IdleTimeoutError{})).To(BeTrue()) }) }) + + Context("Version Negotiation errors", func() { + It("is a Version Negotiation error", func() { + Expect(errors.Is(&VersionNegotiationError{Ours: []protocol.VersionNumber{2, 3}}, &VersionNegotiationError{})).To(BeTrue()) + }) + + It("has a string representation", func() { + Expect((&VersionNegotiationError{ + Ours: []protocol.VersionNumber{2, 3}, + Theirs: []protocol.VersionNumber{4, 5, 6}, + }).Error()).To(Equal("no compatible QUIC version found (we support [0x2 0x3], server offered [0x4 0x5 0x6])")) + }) + }) }) diff --git a/session.go b/session.go index 13820917..180401ce 100644 --- a/session.go +++ b/session.go @@ -132,20 +132,6 @@ func (e *errCloseForRecreating) Is(target error) bool { return ok } -type errVersionNegotiation struct { - ourVersions []protocol.VersionNumber - theirVersions []protocol.VersionNumber -} - -func (e *errVersionNegotiation) Error() string { - return fmt.Sprintf("no compatible QUIC version found (we support %s, server offered %s)", e.ourVersions, e.theirVersions) -} - -func (e *errVersionNegotiation) Is(target error) bool { - _, ok := target.(*errVersionNegotiation) - return ok -} - var sessionTracingID uint64 // to be accessed atomically func nextSessionTracingID() uint64 { return atomic.AddUint64(&sessionTracingID, 1) } @@ -1101,9 +1087,9 @@ func (s *session) handleVersionNegotiationPacket(p *receivedPacket) { } newVersion, ok := protocol.ChooseSupportedVersion(s.config.Versions, supportedVersions) if !ok { - s.destroyImpl(&errVersionNegotiation{ - ourVersions: s.config.Versions, - theirVersions: supportedVersions, + s.destroyImpl(&VersionNegotiationError{ + Ours: s.config.Versions, + Theirs: supportedVersions, }) s.logger.Infof("No compatible QUIC version found.") return @@ -1498,7 +1484,7 @@ func (s *session) handleCloseError(closeErr *closeError) { case errors.Is(e, qerr.ErrIdleTimeout), errors.Is(e, qerr.ErrHandshakeTimeout), errors.Is(e, &statelessResetErr{}), - errors.Is(e, &errVersionNegotiation{}), + errors.Is(e, &VersionNegotiationError{}), errors.Is(e, &errCloseForRecreating{}), errors.Is(e, &qerr.ApplicationError{}), errors.Is(e, &qerr.TransportError{}): @@ -1518,7 +1504,7 @@ func (s *session) handleCloseError(closeErr *closeError) { if s.tracer != nil && !errors.Is(e, &errCloseForRecreating{}) { var ( resetErr *statelessResetErr - vnErr *errVersionNegotiation + vnErr *VersionNegotiationError transportErr *qerr.TransportError applicationErr *qerr.ApplicationError ) @@ -1530,7 +1516,7 @@ func (s *session) handleCloseError(closeErr *closeError) { case errors.As(e, &resetErr): s.tracer.ClosedConnection(logging.NewStatelessResetCloseReason(resetErr.token)) case errors.As(e, &vnErr): - s.tracer.ClosedConnection(logging.NewVersionNegotiationError(vnErr.theirVersions)) + 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):