diff --git a/README.md b/README.md index 4e7c6e461..d1d245dc6 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ [![Windows Build Status](https://img.shields.io/appveyor/ci/lucas-clemente/quic-go/master.svg?style=flat-square&label=windows+build)](https://ci.appveyor.com/project/lucas-clemente/quic-go/branch/master) [![Code Coverage](https://img.shields.io/codecov/c/github/lucas-clemente/quic-go/master.svg?style=flat-square)](https://codecov.io/gh/lucas-clemente/quic-go/) -quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. It implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29). +quic-go is an implementation of the [QUIC](https://en.wikipedia.org/wiki/QUIC) protocol in Go. It implements the [IETF QUIC draft-29](https://tools.ietf.org/html/draft-ietf-quic-transport-29) and [draft-32](https://tools.ietf.org/html/draft-ietf-quic-transport-32). ## Version compatibility diff --git a/conn_id_generator.go b/conn_id_generator.go index dbebe8c84..04649b5dd 100644 --- a/conn_id_generator.go +++ b/conn_id_generator.go @@ -22,6 +22,8 @@ type connIDGenerator struct { retireConnectionID func(protocol.ConnectionID) replaceWithClosed func(protocol.ConnectionID, packetHandler) queueControlFrame func(wire.Frame) + + version protocol.VersionNumber } func newConnIDGenerator( @@ -33,6 +35,7 @@ func newConnIDGenerator( retireConnectionID func(protocol.ConnectionID), replaceWithClosed func(protocol.ConnectionID, packetHandler), queueControlFrame func(wire.Frame), + version protocol.VersionNumber, ) *connIDGenerator { m := &connIDGenerator{ connIDLen: initialConnectionID.Len(), @@ -43,6 +46,7 @@ func newConnIDGenerator( retireConnectionID: retireConnectionID, replaceWithClosed: replaceWithClosed, queueControlFrame: queueControlFrame, + version: version, } m.activeSrcConnIDs[0] = initialConnectionID m.initialClientDestConnID = initialClientDestConnID @@ -76,7 +80,7 @@ func (m *connIDGenerator) Retire(seq uint64, sentWithDestConnID protocol.Connect if !ok { return nil } - if connID.Equal(sentWithDestConnID) && !RetireBugBackwardsCompatibilityMode { + if connID.Equal(sentWithDestConnID) && !protocol.UseRetireBugBackwardsCompatibilityMode(RetireBugBackwardsCompatibilityMode, m.version) { return qerr.NewError(qerr.ProtocolViolation, fmt.Sprintf("tried to retire connection ID %d (%s), which was used as the Destination Connection ID on this packet", seq, connID)) } m.retireConnectionID(connID) @@ -89,7 +93,7 @@ func (m *connIDGenerator) Retire(seq uint64, sentWithDestConnID protocol.Connect } func (m *connIDGenerator) issueNewConnID() error { - if RetireBugBackwardsCompatibilityMode { + if protocol.UseRetireBugBackwardsCompatibilityMode(RetireBugBackwardsCompatibilityMode, m.version) { return nil } connID, err := protocol.GenerateConnectionID(m.connIDLen) diff --git a/conn_id_generator_test.go b/conn_id_generator_test.go index 5ff7e361a..ef8016d95 100644 --- a/conn_id_generator_test.go +++ b/conn_id_generator_test.go @@ -41,6 +41,7 @@ var _ = Describe("Connection ID Generator", func() { func(c protocol.ConnectionID) { retiredConnIDs = append(retiredConnIDs, c) }, func(c protocol.ConnectionID, h packetHandler) { replacedWithClosed[string(c)] = h }, func(f wire.Frame) { queuedFrames = append(queuedFrames, f) }, + protocol.VersionDraft29, ) }) diff --git a/interface.go b/interface.go index a9b8cdeb5..a2fdf1aec 100644 --- a/interface.go +++ b/interface.go @@ -6,10 +6,9 @@ import ( "net" "time" - "github.com/lucas-clemente/quic-go/logging" - "github.com/lucas-clemente/quic-go/internal/handshake" "github.com/lucas-clemente/quic-go/internal/protocol" + "github.com/lucas-clemente/quic-go/logging" "github.com/lucas-clemente/quic-go/quictrace" ) @@ -29,6 +28,13 @@ type StreamID = protocol.StreamID // A VersionNumber is a QUIC version number. type VersionNumber = protocol.VersionNumber +const ( + // VersionDraft29 is IETF QUIC draft-29 + VersionDraft29 = protocol.VersionDraft29 + // VersionDraft32 is IETF QUIC draft-32 + VersionDraft32 = protocol.VersionDraft32 +) + // A Token can be used to verify the ownership of the client address. type Token struct { // IsRetryToken encodes how the client received the token. There are two ways: diff --git a/internal/protocol/version.go b/internal/protocol/version.go index 20c4d7d06..797f00094 100644 --- a/internal/protocol/version.go +++ b/internal/protocol/version.go @@ -21,6 +21,8 @@ const ( VersionTLS VersionNumber = 0x51474fff VersionWhatever VersionNumber = 1 // for when the version doesn't matter VersionUnknown VersionNumber = math.MaxUint32 + VersionDraft29 VersionNumber = 0xff00001d + VersionDraft32 VersionNumber = 0xff000020 ) // SupportedVersions lists the versions that the server supports @@ -38,6 +40,10 @@ func (vn VersionNumber) String() string { return "whatever" case VersionUnknown: return "unknown" + case VersionDraft29: + return "draft-29" + case VersionDraft32: + return "draft-32" case VersionTLS: return "TLS dev version (WIP)" default: @@ -56,6 +62,12 @@ func (vn VersionNumber) toGQUICVersion() int { return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10) } +// UseRetireBugBackwardsCompatibilityMode says if it is necessary to use the backwards compatilibity mode. +// This is only the case if it 1. is enabled and 2. draft-29 is used. +func UseRetireBugBackwardsCompatibilityMode(enabled bool, v VersionNumber) bool { + return enabled && v == VersionDraft29 +} + // IsSupportedVersion returns true if the server supports this version func IsSupportedVersion(supported []VersionNumber, v VersionNumber) bool { for _, t := range supported { diff --git a/internal/protocol/version_test.go b/internal/protocol/version_test.go index c1a989fec..dae3a2fa1 100644 --- a/internal/protocol/version_test.go +++ b/internal/protocol/version_test.go @@ -14,6 +14,8 @@ var _ = Describe("Version", func() { Expect(IsValidVersion(VersionTLS)).To(BeTrue()) Expect(IsValidVersion(VersionWhatever)).To(BeFalse()) Expect(IsValidVersion(VersionUnknown)).To(BeFalse()) + Expect(IsValidVersion(VersionDraft29)).To(BeFalse()) + Expect(IsValidVersion(VersionDraft32)).To(BeFalse()) Expect(IsValidVersion(1234)).To(BeFalse()) }) @@ -25,6 +27,8 @@ var _ = Describe("Version", func() { Expect(VersionTLS.String()).To(ContainSubstring("TLS")) Expect(VersionWhatever.String()).To(Equal("whatever")) Expect(VersionUnknown.String()).To(Equal("unknown")) + Expect(VersionDraft29.String()).To(Equal("draft-29")) + Expect(VersionDraft32.String()).To(Equal("draft-32")) // check with unsupported version numbers from the wiki Expect(VersionNumber(0x51303039).String()).To(Equal("gQUIC 9")) Expect(VersionNumber(0x51303133).String()).To(Equal("gQUIC 13")) @@ -45,6 +49,13 @@ var _ = Describe("Version", func() { } }) + It("says if backwards compatibility mode should be used", func() { + Expect(UseRetireBugBackwardsCompatibilityMode(true, VersionDraft29)).To(BeTrue()) + Expect(UseRetireBugBackwardsCompatibilityMode(true, VersionDraft32)).To(BeFalse()) + Expect(UseRetireBugBackwardsCompatibilityMode(false, VersionDraft29)).To(BeFalse()) + Expect(UseRetireBugBackwardsCompatibilityMode(false, VersionDraft32)).To(BeFalse()) + }) + Context("highest supported version", func() { It("finds the supported version", func() { supportedVersions := []VersionNumber{1, 2, 3} diff --git a/session.go b/session.go index 736b8d4ea..3f8ff2775 100644 --- a/session.go +++ b/session.go @@ -268,6 +268,7 @@ var newSession = func( runner.Retire, runner.ReplaceWithClosed, s.queueControlFrame, + s.version, ) s.preSetup() s.sentPacketHandler, s.receivedPacketHandler = ackhandler.NewAckHandler( @@ -390,6 +391,7 @@ var newClientSession = func( runner.Retire, runner.ReplaceWithClosed, s.queueControlFrame, + s.version, ) s.preSetup() s.sentPacketHandler, s.receivedPacketHandler = ackhandler.NewAckHandler(