quic: error codes and types
Constants for the transport error codes in RFC 9000 Section 20,
types representing transport errors sent to or received from the peer,
and a type representing application protocol errors.
For golang/go#58547
Change-Id: Ib4325e1272f6e0984f233ef494827a1799d7dc26
Reviewed-on: https://go-review.googlesource.com/c/net/+/495235
Reviewed-by: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Damien Neil <dneil@google.com>
diff --git a/internal/quic/errors.go b/internal/quic/errors.go
new file mode 100644
index 0000000..725a7da
--- /dev/null
+++ b/internal/quic/errors.go
@@ -0,0 +1,110 @@
+// Copyright 2023 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 quic
+
+import (
+ "fmt"
+)
+
+// A transportError is an transport error code from RFC 9000 Section 20.1.
+//
+// The transportError type doesn't implement the error interface to ensure we always
+// distinguish between errors sent to and received from the peer.
+// See the localTransportError and peerTransportError types below.
+type transportError uint64
+
+// https://www.rfc-editor.org/rfc/rfc9000.html#section-20.1
+const (
+ errNo = transportError(0x00)
+ errInternal = transportError(0x01)
+ errConnectionRefused = transportError(0x02)
+ errFlowControl = transportError(0x03)
+ errStreamLimit = transportError(0x04)
+ errStreamState = transportError(0x05)
+ errFinalSize = transportError(0x06)
+ errFrameEncoding = transportError(0x07)
+ errTransportParameter = transportError(0x08)
+ errConnectionIDLimit = transportError(0x09)
+ errProtocolViolation = transportError(0x0a)
+ errInvalidToken = transportError(0x0b)
+ errApplicationError = transportError(0x0c)
+ errCryptoBufferExceeded = transportError(0x0d)
+ errKeyUpdateError = transportError(0x0e)
+ errAEADLimitReached = transportError(0x0f)
+ errNoViablePath = transportError(0x10)
+ errTLSBase = transportError(0x0100) // 0x0100-0x01ff; base + TLS code
+)
+
+func (e transportError) String() string {
+ switch e {
+ case errNo:
+ return "NO_ERROR"
+ case errInternal:
+ return "INTERNAL_ERROR"
+ case errConnectionRefused:
+ return "CONNECTION_REFUSED"
+ case errFlowControl:
+ return "FLOW_CONTROL_ERROR"
+ case errStreamLimit:
+ return "STREAM_LIMIT_ERROR"
+ case errStreamState:
+ return "STREAM_STATE_ERROR"
+ case errFinalSize:
+ return "FINAL_SIZE_ERROR"
+ case errFrameEncoding:
+ return "FRAME_ENCODING_ERROR"
+ case errTransportParameter:
+ return "TRANSPORT_PARAMETER_ERROR"
+ case errConnectionIDLimit:
+ return "CONNECTION_ID_LIMIT_ERROR"
+ case errProtocolViolation:
+ return "PROTOCOL_VIOLATION"
+ case errInvalidToken:
+ return "INVALID_TOKEN"
+ case errApplicationError:
+ return "APPLICATION_ERROR"
+ case errCryptoBufferExceeded:
+ return "CRYPTO_BUFFER_EXCEEDED"
+ case errKeyUpdateError:
+ return "KEY_UPDATE_ERROR"
+ case errAEADLimitReached:
+ return "AEAD_LIMIT_REACHED"
+ case errNoViablePath:
+ return "NO_VIABLE_PATH"
+ }
+ if e >= 0x0100 && e <= 0x01ff {
+ return fmt.Sprintf("CRYPTO_ERROR(%v)", uint64(e)&0xff)
+ }
+ return fmt.Sprintf("ERROR %d", uint64(e))
+}
+
+// A localTransportError is an error sent to the peer.
+type localTransportError transportError
+
+func (e localTransportError) Error() string {
+ return "closed connection: " + transportError(e).String()
+}
+
+// A peerTransportError is an error received from the peer.
+type peerTransportError struct {
+ code transportError
+ reason string
+}
+
+func (e peerTransportError) Error() string {
+ return fmt.Sprintf("peer closed connection: %v: %q", e.code, e.reason)
+}
+
+// An ApplicationError is an application protocol error code (RFC 9000, Section 20.2).
+// Application protocol errors may be sent when terminating a stream or connection.
+type ApplicationError struct {
+ Code uint64
+ Reason string
+}
+
+func (e ApplicationError) Error() string {
+ // TODO: Include the Reason string here, but sanitize it first.
+ return fmt.Sprintf("AppError %v", e.Code)
+}