mirror of
https://github.com/golang/net.git
synced 2026-03-31 10:27:08 +09:00
For golang/go#58547 Change-Id: I119d820824f82bfdd236c6826f960d0c934745ca Reviewed-on: https://go-review.googlesource.com/c/net/+/566295 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jonathan Amsterdam <jba@google.com>
728 lines
19 KiB
Go
728 lines
19 KiB
Go
// 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.
|
|
|
|
//go:build go1.21
|
|
|
|
package quic
|
|
|
|
import (
|
|
"fmt"
|
|
"log/slog"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
// A debugFrame is a representation of the contents of a QUIC frame,
|
|
// used for debug logs and testing but not the primary serving path.
|
|
type debugFrame interface {
|
|
String() string
|
|
write(w *packetWriter) bool
|
|
LogValue() slog.Value
|
|
}
|
|
|
|
func parseDebugFrame(b []byte) (f debugFrame, n int) {
|
|
if len(b) == 0 {
|
|
return nil, -1
|
|
}
|
|
switch b[0] {
|
|
case frameTypePadding:
|
|
f, n = parseDebugFramePadding(b)
|
|
case frameTypePing:
|
|
f, n = parseDebugFramePing(b)
|
|
case frameTypeAck, frameTypeAckECN:
|
|
f, n = parseDebugFrameAck(b)
|
|
case frameTypeResetStream:
|
|
f, n = parseDebugFrameResetStream(b)
|
|
case frameTypeStopSending:
|
|
f, n = parseDebugFrameStopSending(b)
|
|
case frameTypeCrypto:
|
|
f, n = parseDebugFrameCrypto(b)
|
|
case frameTypeNewToken:
|
|
f, n = parseDebugFrameNewToken(b)
|
|
case frameTypeStreamBase, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f:
|
|
f, n = parseDebugFrameStream(b)
|
|
case frameTypeMaxData:
|
|
f, n = parseDebugFrameMaxData(b)
|
|
case frameTypeMaxStreamData:
|
|
f, n = parseDebugFrameMaxStreamData(b)
|
|
case frameTypeMaxStreamsBidi, frameTypeMaxStreamsUni:
|
|
f, n = parseDebugFrameMaxStreams(b)
|
|
case frameTypeDataBlocked:
|
|
f, n = parseDebugFrameDataBlocked(b)
|
|
case frameTypeStreamDataBlocked:
|
|
f, n = parseDebugFrameStreamDataBlocked(b)
|
|
case frameTypeStreamsBlockedBidi, frameTypeStreamsBlockedUni:
|
|
f, n = parseDebugFrameStreamsBlocked(b)
|
|
case frameTypeNewConnectionID:
|
|
f, n = parseDebugFrameNewConnectionID(b)
|
|
case frameTypeRetireConnectionID:
|
|
f, n = parseDebugFrameRetireConnectionID(b)
|
|
case frameTypePathChallenge:
|
|
f, n = parseDebugFramePathChallenge(b)
|
|
case frameTypePathResponse:
|
|
f, n = parseDebugFramePathResponse(b)
|
|
case frameTypeConnectionCloseTransport:
|
|
f, n = parseDebugFrameConnectionCloseTransport(b)
|
|
case frameTypeConnectionCloseApplication:
|
|
f, n = parseDebugFrameConnectionCloseApplication(b)
|
|
case frameTypeHandshakeDone:
|
|
f, n = parseDebugFrameHandshakeDone(b)
|
|
default:
|
|
return nil, -1
|
|
}
|
|
return f, n
|
|
}
|
|
|
|
// debugFramePadding is a sequence of PADDING frames.
|
|
type debugFramePadding struct {
|
|
size int
|
|
to int // alternate for writing packets: pad to
|
|
}
|
|
|
|
func parseDebugFramePadding(b []byte) (f debugFramePadding, n int) {
|
|
for n < len(b) && b[n] == frameTypePadding {
|
|
n++
|
|
}
|
|
f.size = n
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFramePadding) String() string {
|
|
return fmt.Sprintf("PADDING*%v", f.size)
|
|
}
|
|
|
|
func (f debugFramePadding) write(w *packetWriter) bool {
|
|
if w.avail() == 0 {
|
|
return false
|
|
}
|
|
if f.to > 0 {
|
|
w.appendPaddingTo(f.to)
|
|
return true
|
|
}
|
|
for i := 0; i < f.size && w.avail() > 0; i++ {
|
|
w.b = append(w.b, frameTypePadding)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (f debugFramePadding) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "padding"),
|
|
slog.Int("length", f.size),
|
|
)
|
|
}
|
|
|
|
// debugFramePing is a PING frame.
|
|
type debugFramePing struct{}
|
|
|
|
func parseDebugFramePing(b []byte) (f debugFramePing, n int) {
|
|
return f, 1
|
|
}
|
|
|
|
func (f debugFramePing) String() string {
|
|
return "PING"
|
|
}
|
|
|
|
func (f debugFramePing) write(w *packetWriter) bool {
|
|
return w.appendPingFrame()
|
|
}
|
|
|
|
func (f debugFramePing) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "ping"),
|
|
)
|
|
}
|
|
|
|
// debugFrameAck is an ACK frame.
|
|
type debugFrameAck struct {
|
|
ackDelay unscaledAckDelay
|
|
ranges []i64range[packetNumber]
|
|
}
|
|
|
|
func parseDebugFrameAck(b []byte) (f debugFrameAck, n int) {
|
|
f.ranges = nil
|
|
_, f.ackDelay, n = consumeAckFrame(b, func(_ int, start, end packetNumber) {
|
|
f.ranges = append(f.ranges, i64range[packetNumber]{
|
|
start: start,
|
|
end: end,
|
|
})
|
|
})
|
|
// Ranges are parsed high to low; reverse ranges slice to order them low to high.
|
|
for i := 0; i < len(f.ranges)/2; i++ {
|
|
j := len(f.ranges) - 1
|
|
f.ranges[i], f.ranges[j] = f.ranges[j], f.ranges[i]
|
|
}
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameAck) String() string {
|
|
s := fmt.Sprintf("ACK Delay=%v", f.ackDelay)
|
|
for _, r := range f.ranges {
|
|
s += fmt.Sprintf(" [%v,%v)", r.start, r.end)
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (f debugFrameAck) write(w *packetWriter) bool {
|
|
return w.appendAckFrame(rangeset[packetNumber](f.ranges), f.ackDelay)
|
|
}
|
|
|
|
func (f debugFrameAck) LogValue() slog.Value {
|
|
return slog.StringValue("error: debugFrameAck should not appear as a slog Value")
|
|
}
|
|
|
|
// debugFrameScaledAck is an ACK frame with scaled ACK Delay.
|
|
//
|
|
// This type is used in qlog events, which need access to the delay as a duration.
|
|
type debugFrameScaledAck struct {
|
|
ackDelay time.Duration
|
|
ranges []i64range[packetNumber]
|
|
}
|
|
|
|
func (f debugFrameScaledAck) LogValue() slog.Value {
|
|
var ackDelay slog.Attr
|
|
if f.ackDelay >= 0 {
|
|
ackDelay = slog.Duration("ack_delay", f.ackDelay)
|
|
}
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "ack"),
|
|
// Rather than trying to convert the ack ranges into the slog data model,
|
|
// pass a value that can JSON-encode itself.
|
|
slog.Any("acked_ranges", debugAckRanges(f.ranges)),
|
|
ackDelay,
|
|
)
|
|
}
|
|
|
|
type debugAckRanges []i64range[packetNumber]
|
|
|
|
// AppendJSON appends a JSON encoding of the ack ranges to b, and returns it.
|
|
// This is different than the standard json.Marshaler, but more efficient.
|
|
// Since we only use this in cooperation with the qlog package,
|
|
// encoding/json compatibility is irrelevant.
|
|
func (r debugAckRanges) AppendJSON(b []byte) []byte {
|
|
b = append(b, '[')
|
|
for i, ar := range r {
|
|
start, end := ar.start, ar.end-1 // qlog ranges are closed-closed
|
|
if i != 0 {
|
|
b = append(b, ',')
|
|
}
|
|
b = append(b, '[')
|
|
b = strconv.AppendInt(b, int64(start), 10)
|
|
if start != end {
|
|
b = append(b, ',')
|
|
b = strconv.AppendInt(b, int64(end), 10)
|
|
}
|
|
b = append(b, ']')
|
|
}
|
|
b = append(b, ']')
|
|
return b
|
|
}
|
|
|
|
func (r debugAckRanges) String() string {
|
|
return string(r.AppendJSON(nil))
|
|
}
|
|
|
|
// debugFrameResetStream is a RESET_STREAM frame.
|
|
type debugFrameResetStream struct {
|
|
id streamID
|
|
code uint64
|
|
finalSize int64
|
|
}
|
|
|
|
func parseDebugFrameResetStream(b []byte) (f debugFrameResetStream, n int) {
|
|
f.id, f.code, f.finalSize, n = consumeResetStreamFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameResetStream) String() string {
|
|
return fmt.Sprintf("RESET_STREAM ID=%v Code=%v FinalSize=%v", f.id, f.code, f.finalSize)
|
|
}
|
|
|
|
func (f debugFrameResetStream) write(w *packetWriter) bool {
|
|
return w.appendResetStreamFrame(f.id, f.code, f.finalSize)
|
|
}
|
|
|
|
func (f debugFrameResetStream) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "reset_stream"),
|
|
slog.Uint64("stream_id", uint64(f.id)),
|
|
slog.Uint64("final_size", uint64(f.finalSize)),
|
|
)
|
|
}
|
|
|
|
// debugFrameStopSending is a STOP_SENDING frame.
|
|
type debugFrameStopSending struct {
|
|
id streamID
|
|
code uint64
|
|
}
|
|
|
|
func parseDebugFrameStopSending(b []byte) (f debugFrameStopSending, n int) {
|
|
f.id, f.code, n = consumeStopSendingFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameStopSending) String() string {
|
|
return fmt.Sprintf("STOP_SENDING ID=%v Code=%v", f.id, f.code)
|
|
}
|
|
|
|
func (f debugFrameStopSending) write(w *packetWriter) bool {
|
|
return w.appendStopSendingFrame(f.id, f.code)
|
|
}
|
|
|
|
func (f debugFrameStopSending) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "stop_sending"),
|
|
slog.Uint64("stream_id", uint64(f.id)),
|
|
slog.Uint64("error_code", uint64(f.code)),
|
|
)
|
|
}
|
|
|
|
// debugFrameCrypto is a CRYPTO frame.
|
|
type debugFrameCrypto struct {
|
|
off int64
|
|
data []byte
|
|
}
|
|
|
|
func parseDebugFrameCrypto(b []byte) (f debugFrameCrypto, n int) {
|
|
f.off, f.data, n = consumeCryptoFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameCrypto) String() string {
|
|
return fmt.Sprintf("CRYPTO Offset=%v Length=%v", f.off, len(f.data))
|
|
}
|
|
|
|
func (f debugFrameCrypto) write(w *packetWriter) bool {
|
|
b, added := w.appendCryptoFrame(f.off, len(f.data))
|
|
copy(b, f.data)
|
|
return added
|
|
}
|
|
|
|
func (f debugFrameCrypto) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "crypto"),
|
|
slog.Int64("offset", f.off),
|
|
slog.Int("length", len(f.data)),
|
|
)
|
|
}
|
|
|
|
// debugFrameNewToken is a NEW_TOKEN frame.
|
|
type debugFrameNewToken struct {
|
|
token []byte
|
|
}
|
|
|
|
func parseDebugFrameNewToken(b []byte) (f debugFrameNewToken, n int) {
|
|
f.token, n = consumeNewTokenFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameNewToken) String() string {
|
|
return fmt.Sprintf("NEW_TOKEN Token=%x", f.token)
|
|
}
|
|
|
|
func (f debugFrameNewToken) write(w *packetWriter) bool {
|
|
return w.appendNewTokenFrame(f.token)
|
|
}
|
|
|
|
func (f debugFrameNewToken) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "new_token"),
|
|
slogHexstring("token", f.token),
|
|
)
|
|
}
|
|
|
|
// debugFrameStream is a STREAM frame.
|
|
type debugFrameStream struct {
|
|
id streamID
|
|
fin bool
|
|
off int64
|
|
data []byte
|
|
}
|
|
|
|
func parseDebugFrameStream(b []byte) (f debugFrameStream, n int) {
|
|
f.id, f.off, f.fin, f.data, n = consumeStreamFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameStream) String() string {
|
|
fin := ""
|
|
if f.fin {
|
|
fin = " FIN"
|
|
}
|
|
return fmt.Sprintf("STREAM ID=%v%v Offset=%v Length=%v", f.id, fin, f.off, len(f.data))
|
|
}
|
|
|
|
func (f debugFrameStream) write(w *packetWriter) bool {
|
|
b, added := w.appendStreamFrame(f.id, f.off, len(f.data), f.fin)
|
|
copy(b, f.data)
|
|
return added
|
|
}
|
|
|
|
func (f debugFrameStream) LogValue() slog.Value {
|
|
var fin slog.Attr
|
|
if f.fin {
|
|
fin = slog.Bool("fin", true)
|
|
}
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "stream"),
|
|
slog.Uint64("stream_id", uint64(f.id)),
|
|
slog.Int64("offset", f.off),
|
|
slog.Int("length", len(f.data)),
|
|
fin,
|
|
)
|
|
}
|
|
|
|
// debugFrameMaxData is a MAX_DATA frame.
|
|
type debugFrameMaxData struct {
|
|
max int64
|
|
}
|
|
|
|
func parseDebugFrameMaxData(b []byte) (f debugFrameMaxData, n int) {
|
|
f.max, n = consumeMaxDataFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameMaxData) String() string {
|
|
return fmt.Sprintf("MAX_DATA Max=%v", f.max)
|
|
}
|
|
|
|
func (f debugFrameMaxData) write(w *packetWriter) bool {
|
|
return w.appendMaxDataFrame(f.max)
|
|
}
|
|
|
|
func (f debugFrameMaxData) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "max_data"),
|
|
slog.Int64("maximum", f.max),
|
|
)
|
|
}
|
|
|
|
// debugFrameMaxStreamData is a MAX_STREAM_DATA frame.
|
|
type debugFrameMaxStreamData struct {
|
|
id streamID
|
|
max int64
|
|
}
|
|
|
|
func parseDebugFrameMaxStreamData(b []byte) (f debugFrameMaxStreamData, n int) {
|
|
f.id, f.max, n = consumeMaxStreamDataFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameMaxStreamData) String() string {
|
|
return fmt.Sprintf("MAX_STREAM_DATA ID=%v Max=%v", f.id, f.max)
|
|
}
|
|
|
|
func (f debugFrameMaxStreamData) write(w *packetWriter) bool {
|
|
return w.appendMaxStreamDataFrame(f.id, f.max)
|
|
}
|
|
|
|
func (f debugFrameMaxStreamData) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "max_stream_data"),
|
|
slog.Uint64("stream_id", uint64(f.id)),
|
|
slog.Int64("maximum", f.max),
|
|
)
|
|
}
|
|
|
|
// debugFrameMaxStreams is a MAX_STREAMS frame.
|
|
type debugFrameMaxStreams struct {
|
|
streamType streamType
|
|
max int64
|
|
}
|
|
|
|
func parseDebugFrameMaxStreams(b []byte) (f debugFrameMaxStreams, n int) {
|
|
f.streamType, f.max, n = consumeMaxStreamsFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameMaxStreams) String() string {
|
|
return fmt.Sprintf("MAX_STREAMS Type=%v Max=%v", f.streamType, f.max)
|
|
}
|
|
|
|
func (f debugFrameMaxStreams) write(w *packetWriter) bool {
|
|
return w.appendMaxStreamsFrame(f.streamType, f.max)
|
|
}
|
|
|
|
func (f debugFrameMaxStreams) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "max_streams"),
|
|
slog.String("stream_type", f.streamType.qlogString()),
|
|
slog.Int64("maximum", f.max),
|
|
)
|
|
}
|
|
|
|
// debugFrameDataBlocked is a DATA_BLOCKED frame.
|
|
type debugFrameDataBlocked struct {
|
|
max int64
|
|
}
|
|
|
|
func parseDebugFrameDataBlocked(b []byte) (f debugFrameDataBlocked, n int) {
|
|
f.max, n = consumeDataBlockedFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameDataBlocked) String() string {
|
|
return fmt.Sprintf("DATA_BLOCKED Max=%v", f.max)
|
|
}
|
|
|
|
func (f debugFrameDataBlocked) write(w *packetWriter) bool {
|
|
return w.appendDataBlockedFrame(f.max)
|
|
}
|
|
|
|
func (f debugFrameDataBlocked) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "data_blocked"),
|
|
slog.Int64("limit", f.max),
|
|
)
|
|
}
|
|
|
|
// debugFrameStreamDataBlocked is a STREAM_DATA_BLOCKED frame.
|
|
type debugFrameStreamDataBlocked struct {
|
|
id streamID
|
|
max int64
|
|
}
|
|
|
|
func parseDebugFrameStreamDataBlocked(b []byte) (f debugFrameStreamDataBlocked, n int) {
|
|
f.id, f.max, n = consumeStreamDataBlockedFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameStreamDataBlocked) String() string {
|
|
return fmt.Sprintf("STREAM_DATA_BLOCKED ID=%v Max=%v", f.id, f.max)
|
|
}
|
|
|
|
func (f debugFrameStreamDataBlocked) write(w *packetWriter) bool {
|
|
return w.appendStreamDataBlockedFrame(f.id, f.max)
|
|
}
|
|
|
|
func (f debugFrameStreamDataBlocked) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "stream_data_blocked"),
|
|
slog.Uint64("stream_id", uint64(f.id)),
|
|
slog.Int64("limit", f.max),
|
|
)
|
|
}
|
|
|
|
// debugFrameStreamsBlocked is a STREAMS_BLOCKED frame.
|
|
type debugFrameStreamsBlocked struct {
|
|
streamType streamType
|
|
max int64
|
|
}
|
|
|
|
func parseDebugFrameStreamsBlocked(b []byte) (f debugFrameStreamsBlocked, n int) {
|
|
f.streamType, f.max, n = consumeStreamsBlockedFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameStreamsBlocked) String() string {
|
|
return fmt.Sprintf("STREAMS_BLOCKED Type=%v Max=%v", f.streamType, f.max)
|
|
}
|
|
|
|
func (f debugFrameStreamsBlocked) write(w *packetWriter) bool {
|
|
return w.appendStreamsBlockedFrame(f.streamType, f.max)
|
|
}
|
|
|
|
func (f debugFrameStreamsBlocked) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "streams_blocked"),
|
|
slog.String("stream_type", f.streamType.qlogString()),
|
|
slog.Int64("limit", f.max),
|
|
)
|
|
}
|
|
|
|
// debugFrameNewConnectionID is a NEW_CONNECTION_ID frame.
|
|
type debugFrameNewConnectionID struct {
|
|
seq int64
|
|
retirePriorTo int64
|
|
connID []byte
|
|
token statelessResetToken
|
|
}
|
|
|
|
func parseDebugFrameNewConnectionID(b []byte) (f debugFrameNewConnectionID, n int) {
|
|
f.seq, f.retirePriorTo, f.connID, f.token, n = consumeNewConnectionIDFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameNewConnectionID) String() string {
|
|
return fmt.Sprintf("NEW_CONNECTION_ID Seq=%v Retire=%v ID=%x Token=%x", f.seq, f.retirePriorTo, f.connID, f.token[:])
|
|
}
|
|
|
|
func (f debugFrameNewConnectionID) write(w *packetWriter) bool {
|
|
return w.appendNewConnectionIDFrame(f.seq, f.retirePriorTo, f.connID, f.token)
|
|
}
|
|
|
|
func (f debugFrameNewConnectionID) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "new_connection_id"),
|
|
slog.Int64("sequence_number", f.seq),
|
|
slog.Int64("retire_prior_to", f.retirePriorTo),
|
|
slogHexstring("connection_id", f.connID),
|
|
slogHexstring("stateless_reset_token", f.token[:]),
|
|
)
|
|
}
|
|
|
|
// debugFrameRetireConnectionID is a NEW_CONNECTION_ID frame.
|
|
type debugFrameRetireConnectionID struct {
|
|
seq int64
|
|
}
|
|
|
|
func parseDebugFrameRetireConnectionID(b []byte) (f debugFrameRetireConnectionID, n int) {
|
|
f.seq, n = consumeRetireConnectionIDFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameRetireConnectionID) String() string {
|
|
return fmt.Sprintf("RETIRE_CONNECTION_ID Seq=%v", f.seq)
|
|
}
|
|
|
|
func (f debugFrameRetireConnectionID) write(w *packetWriter) bool {
|
|
return w.appendRetireConnectionIDFrame(f.seq)
|
|
}
|
|
|
|
func (f debugFrameRetireConnectionID) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "retire_connection_id"),
|
|
slog.Int64("sequence_number", f.seq),
|
|
)
|
|
}
|
|
|
|
// debugFramePathChallenge is a PATH_CHALLENGE frame.
|
|
type debugFramePathChallenge struct {
|
|
data pathChallengeData
|
|
}
|
|
|
|
func parseDebugFramePathChallenge(b []byte) (f debugFramePathChallenge, n int) {
|
|
f.data, n = consumePathChallengeFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFramePathChallenge) String() string {
|
|
return fmt.Sprintf("PATH_CHALLENGE Data=%x", f.data)
|
|
}
|
|
|
|
func (f debugFramePathChallenge) write(w *packetWriter) bool {
|
|
return w.appendPathChallengeFrame(f.data)
|
|
}
|
|
|
|
func (f debugFramePathChallenge) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "path_challenge"),
|
|
slog.String("data", fmt.Sprintf("%x", f.data)),
|
|
)
|
|
}
|
|
|
|
// debugFramePathResponse is a PATH_RESPONSE frame.
|
|
type debugFramePathResponse struct {
|
|
data pathChallengeData
|
|
}
|
|
|
|
func parseDebugFramePathResponse(b []byte) (f debugFramePathResponse, n int) {
|
|
f.data, n = consumePathResponseFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFramePathResponse) String() string {
|
|
return fmt.Sprintf("PATH_RESPONSE Data=%x", f.data)
|
|
}
|
|
|
|
func (f debugFramePathResponse) write(w *packetWriter) bool {
|
|
return w.appendPathResponseFrame(f.data)
|
|
}
|
|
|
|
func (f debugFramePathResponse) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "path_response"),
|
|
slog.String("data", fmt.Sprintf("%x", f.data)),
|
|
)
|
|
}
|
|
|
|
// debugFrameConnectionCloseTransport is a CONNECTION_CLOSE frame carrying a transport error.
|
|
type debugFrameConnectionCloseTransport struct {
|
|
code transportError
|
|
frameType uint64
|
|
reason string
|
|
}
|
|
|
|
func parseDebugFrameConnectionCloseTransport(b []byte) (f debugFrameConnectionCloseTransport, n int) {
|
|
f.code, f.frameType, f.reason, n = consumeConnectionCloseTransportFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameConnectionCloseTransport) String() string {
|
|
s := fmt.Sprintf("CONNECTION_CLOSE Code=%v", f.code)
|
|
if f.frameType != 0 {
|
|
s += fmt.Sprintf(" FrameType=%v", f.frameType)
|
|
}
|
|
if f.reason != "" {
|
|
s += fmt.Sprintf(" Reason=%q", f.reason)
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (f debugFrameConnectionCloseTransport) write(w *packetWriter) bool {
|
|
return w.appendConnectionCloseTransportFrame(f.code, f.frameType, f.reason)
|
|
}
|
|
|
|
func (f debugFrameConnectionCloseTransport) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "connection_close"),
|
|
slog.String("error_space", "transport"),
|
|
slog.Uint64("error_code_value", uint64(f.code)),
|
|
slog.String("reason", f.reason),
|
|
)
|
|
}
|
|
|
|
// debugFrameConnectionCloseApplication is a CONNECTION_CLOSE frame carrying an application error.
|
|
type debugFrameConnectionCloseApplication struct {
|
|
code uint64
|
|
reason string
|
|
}
|
|
|
|
func parseDebugFrameConnectionCloseApplication(b []byte) (f debugFrameConnectionCloseApplication, n int) {
|
|
f.code, f.reason, n = consumeConnectionCloseApplicationFrame(b)
|
|
return f, n
|
|
}
|
|
|
|
func (f debugFrameConnectionCloseApplication) String() string {
|
|
s := fmt.Sprintf("CONNECTION_CLOSE AppCode=%v", f.code)
|
|
if f.reason != "" {
|
|
s += fmt.Sprintf(" Reason=%q", f.reason)
|
|
}
|
|
return s
|
|
}
|
|
|
|
func (f debugFrameConnectionCloseApplication) write(w *packetWriter) bool {
|
|
return w.appendConnectionCloseApplicationFrame(f.code, f.reason)
|
|
}
|
|
|
|
func (f debugFrameConnectionCloseApplication) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "connection_close"),
|
|
slog.String("error_space", "application"),
|
|
slog.Uint64("error_code_value", uint64(f.code)),
|
|
slog.String("reason", f.reason),
|
|
)
|
|
}
|
|
|
|
// debugFrameHandshakeDone is a HANDSHAKE_DONE frame.
|
|
type debugFrameHandshakeDone struct{}
|
|
|
|
func parseDebugFrameHandshakeDone(b []byte) (f debugFrameHandshakeDone, n int) {
|
|
return f, 1
|
|
}
|
|
|
|
func (f debugFrameHandshakeDone) String() string {
|
|
return "HANDSHAKE_DONE"
|
|
}
|
|
|
|
func (f debugFrameHandshakeDone) write(w *packetWriter) bool {
|
|
return w.appendHandshakeDoneFrame()
|
|
}
|
|
|
|
func (f debugFrameHandshakeDone) LogValue() slog.Value {
|
|
return slog.GroupValue(
|
|
slog.String("frame_type", "handshake_done"),
|
|
)
|
|
}
|