uquic/qlog/frame.go
2020-07-02 16:41:43 +07:00

250 lines
7.5 KiB
Go

package qlog
import (
"fmt"
"github.com/francoispqt/gojay"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/wire"
)
type frame struct {
Frame interface{}
}
var _ gojay.MarshalerJSONObject = frame{}
type frames []frame
func (fs frames) IsNil() bool { return fs == nil }
func (fs frames) MarshalJSONArray(enc *gojay.Encoder) {
for _, f := range fs {
enc.Object(f)
}
}
var _ gojay.MarshalerJSONArray = frames{}
type cryptoFrame struct {
Offset protocol.ByteCount
Length protocol.ByteCount
}
type streamFrame struct {
StreamID protocol.StreamID
Offset protocol.ByteCount
Length protocol.ByteCount
FinBit bool
}
func transformFrame(wf wire.Frame) *frame {
// We don't want to store CRYPTO and STREAM frames, for multiple reasons:
// * They both contain data, and we want to make this byte slice GC'able as soon as possible.
// * STREAM frames use a slice from the buffer pool, which is released as soon as the frame is processed.
switch f := wf.(type) {
case *wire.CryptoFrame:
return &frame{Frame: &cryptoFrame{
Offset: f.Offset,
Length: protocol.ByteCount(len(f.Data)),
}}
case *wire.StreamFrame:
return &frame{Frame: &streamFrame{
StreamID: f.StreamID,
Offset: f.Offset,
Length: f.DataLen(),
FinBit: f.Fin,
}}
default:
return &frame{Frame: wf}
}
}
func (f frame) MarshalJSONObject(enc *gojay.Encoder) {
switch frame := f.Frame.(type) {
case *wire.PingFrame:
marshalPingFrame(enc, frame)
case *wire.AckFrame:
marshalAckFrame(enc, frame)
case *wire.ResetStreamFrame:
marshalResetStreamFrame(enc, frame)
case *wire.StopSendingFrame:
marshalStopSendingFrame(enc, frame)
case *cryptoFrame:
marshalCryptoFrame(enc, frame)
case *wire.NewTokenFrame:
marshalNewTokenFrame(enc, frame)
case *streamFrame:
marshalStreamFrame(enc, frame)
case *wire.MaxDataFrame:
marshalMaxDataFrame(enc, frame)
case *wire.MaxStreamDataFrame:
marshalMaxStreamDataFrame(enc, frame)
case *wire.MaxStreamsFrame:
marshalMaxStreamsFrame(enc, frame)
case *wire.DataBlockedFrame:
marshalDataBlockedFrame(enc, frame)
case *wire.StreamDataBlockedFrame:
marshalStreamDataBlockedFrame(enc, frame)
case *wire.StreamsBlockedFrame:
marshalStreamsBlockedFrame(enc, frame)
case *wire.NewConnectionIDFrame:
marshalNewConnectionIDFrame(enc, frame)
case *wire.RetireConnectionIDFrame:
marshalRetireConnectionIDFrame(enc, frame)
case *wire.PathChallengeFrame:
marshalPathChallengeFrame(enc, frame)
case *wire.PathResponseFrame:
marshalPathResponseFrame(enc, frame)
case *wire.ConnectionCloseFrame:
marshalConnectionCloseFrame(enc, frame)
case *wire.HandshakeDoneFrame:
marshalHandshakeDoneFrame(enc, frame)
default:
panic("unknown frame type")
}
}
func (f frame) IsNil() bool { return false }
func marshalPingFrame(enc *gojay.Encoder, _ *wire.PingFrame) {
enc.StringKey("frame_type", "ping")
}
type ackRanges []wire.AckRange
func (ars ackRanges) MarshalJSONArray(enc *gojay.Encoder) {
for _, r := range ars {
enc.Array(ackRange(r))
}
}
func (ars ackRanges) IsNil() bool { return false }
type ackRange wire.AckRange
func (ar ackRange) MarshalJSONArray(enc *gojay.Encoder) {
enc.AddInt64(int64(ar.Smallest))
if ar.Smallest != ar.Largest {
enc.AddInt64(int64(ar.Largest))
}
}
func (ar ackRange) IsNil() bool { return false }
func marshalAckFrame(enc *gojay.Encoder, f *wire.AckFrame) {
enc.StringKey("frame_type", "ack")
enc.FloatKeyOmitEmpty("ack_delay", milliseconds(f.DelayTime))
enc.ArrayKey("acked_ranges", ackRanges(f.AckRanges))
}
func marshalResetStreamFrame(enc *gojay.Encoder, f *wire.ResetStreamFrame) {
enc.StringKey("frame_type", "reset_stream")
enc.Int64Key("stream_id", int64(f.StreamID))
enc.Int64Key("error_code", int64(f.ErrorCode))
enc.Int64Key("final_size", int64(f.FinalSize))
}
func marshalStopSendingFrame(enc *gojay.Encoder, f *wire.StopSendingFrame) {
enc.StringKey("frame_type", "stop_sending")
enc.Int64Key("stream_id", int64(f.StreamID))
enc.Int64Key("error_code", int64(f.ErrorCode))
}
func marshalCryptoFrame(enc *gojay.Encoder, f *cryptoFrame) {
enc.StringKey("frame_type", "crypto")
enc.Int64Key("offset", int64(f.Offset))
enc.Int64Key("length", int64(f.Length))
}
func marshalNewTokenFrame(enc *gojay.Encoder, f *wire.NewTokenFrame) {
enc.StringKey("frame_type", "new_token")
enc.IntKey("length", len(f.Token))
enc.StringKey("token", fmt.Sprintf("%x", f.Token))
}
func marshalStreamFrame(enc *gojay.Encoder, f *streamFrame) {
enc.StringKey("frame_type", "stream")
enc.Int64Key("stream_id", int64(f.StreamID))
enc.Int64Key("offset", int64(f.Offset))
enc.IntKey("length", int(f.Length))
enc.BoolKeyOmitEmpty("fin", f.FinBit)
}
func marshalMaxDataFrame(enc *gojay.Encoder, f *wire.MaxDataFrame) {
enc.StringKey("frame_type", "max_data")
enc.Int64Key("maximum", int64(f.MaximumData))
}
func marshalMaxStreamDataFrame(enc *gojay.Encoder, f *wire.MaxStreamDataFrame) {
enc.StringKey("frame_type", "max_stream_data")
enc.Int64Key("stream_id", int64(f.StreamID))
enc.Int64Key("maximum", int64(f.MaximumStreamData))
}
func marshalMaxStreamsFrame(enc *gojay.Encoder, f *wire.MaxStreamsFrame) {
enc.StringKey("frame_type", "max_streams")
enc.StringKey("stream_type", streamType(f.Type).String())
enc.Int64Key("maximum", int64(f.MaxStreamNum))
}
func marshalDataBlockedFrame(enc *gojay.Encoder, f *wire.DataBlockedFrame) {
enc.StringKey("frame_type", "data_blocked")
enc.Int64Key("limit", int64(f.MaximumData))
}
func marshalStreamDataBlockedFrame(enc *gojay.Encoder, f *wire.StreamDataBlockedFrame) {
enc.StringKey("frame_type", "stream_data_blocked")
enc.Int64Key("stream_id", int64(f.StreamID))
enc.Int64Key("limit", int64(f.MaximumStreamData))
}
func marshalStreamsBlockedFrame(enc *gojay.Encoder, f *wire.StreamsBlockedFrame) {
enc.StringKey("frame_type", "streams_blocked")
enc.StringKey("stream_type", streamType(f.Type).String())
enc.Int64Key("limit", int64(f.StreamLimit))
}
func marshalNewConnectionIDFrame(enc *gojay.Encoder, f *wire.NewConnectionIDFrame) {
enc.StringKey("frame_type", "new_connection_id")
enc.Int64Key("sequence_number", int64(f.SequenceNumber))
enc.Int64Key("retire_prior_to", int64(f.RetirePriorTo))
enc.IntKey("length", f.ConnectionID.Len())
enc.StringKey("connection_id", connectionID(f.ConnectionID).String())
enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", f.StatelessResetToken))
}
func marshalRetireConnectionIDFrame(enc *gojay.Encoder, f *wire.RetireConnectionIDFrame) {
enc.StringKey("frame_type", "retire_connection_id")
enc.Int64Key("sequence_number", int64(f.SequenceNumber))
}
func marshalPathChallengeFrame(enc *gojay.Encoder, f *wire.PathChallengeFrame) {
enc.StringKey("frame_type", "path_challenge")
enc.StringKey("data", fmt.Sprintf("%x", f.Data[:]))
}
func marshalPathResponseFrame(enc *gojay.Encoder, f *wire.PathResponseFrame) {
enc.StringKey("frame_type", "path_response")
enc.StringKey("data", fmt.Sprintf("%x", f.Data[:]))
}
func marshalConnectionCloseFrame(enc *gojay.Encoder, f *wire.ConnectionCloseFrame) {
errorSpace := "transport"
if f.IsApplicationError {
errorSpace = "application"
}
enc.StringKey("frame_type", "connection_close")
enc.StringKey("error_space", errorSpace)
if errName := transportError(f.ErrorCode).String(); len(errName) > 0 {
enc.StringKey("error_code", errName)
} else {
enc.Uint64Key("error_code", uint64(f.ErrorCode))
}
enc.Uint64Key("raw_error_code", uint64(f.ErrorCode))
enc.StringKey("reason", f.ReasonPhrase)
}
func marshalHandshakeDoneFrame(enc *gojay.Encoder, _ *wire.HandshakeDoneFrame) {
enc.StringKey("frame_type", "handshake_done")
}