github.com/sagernet/quic-go@v0.43.1-beta.1/qlog/frame.go (about) 1 package qlog 2 3 import ( 4 "fmt" 5 6 "github.com/francoispqt/gojay" 7 "github.com/sagernet/quic-go/internal/wire" 8 "github.com/sagernet/quic-go/logging" 9 ) 10 11 type frame struct { 12 Frame logging.Frame 13 } 14 15 var _ gojay.MarshalerJSONObject = frame{} 16 17 var _ gojay.MarshalerJSONArray = frames{} 18 19 func (f frame) MarshalJSONObject(enc *gojay.Encoder) { 20 switch frame := f.Frame.(type) { 21 case *logging.PingFrame: 22 marshalPingFrame(enc, frame) 23 case *logging.AckFrame: 24 marshalAckFrame(enc, frame) 25 case *logging.ResetStreamFrame: 26 marshalResetStreamFrame(enc, frame) 27 case *logging.StopSendingFrame: 28 marshalStopSendingFrame(enc, frame) 29 case *logging.CryptoFrame: 30 marshalCryptoFrame(enc, frame) 31 case *logging.NewTokenFrame: 32 marshalNewTokenFrame(enc, frame) 33 case *logging.StreamFrame: 34 marshalStreamFrame(enc, frame) 35 case *logging.MaxDataFrame: 36 marshalMaxDataFrame(enc, frame) 37 case *logging.MaxStreamDataFrame: 38 marshalMaxStreamDataFrame(enc, frame) 39 case *logging.MaxStreamsFrame: 40 marshalMaxStreamsFrame(enc, frame) 41 case *logging.DataBlockedFrame: 42 marshalDataBlockedFrame(enc, frame) 43 case *logging.StreamDataBlockedFrame: 44 marshalStreamDataBlockedFrame(enc, frame) 45 case *logging.StreamsBlockedFrame: 46 marshalStreamsBlockedFrame(enc, frame) 47 case *logging.NewConnectionIDFrame: 48 marshalNewConnectionIDFrame(enc, frame) 49 case *logging.RetireConnectionIDFrame: 50 marshalRetireConnectionIDFrame(enc, frame) 51 case *logging.PathChallengeFrame: 52 marshalPathChallengeFrame(enc, frame) 53 case *logging.PathResponseFrame: 54 marshalPathResponseFrame(enc, frame) 55 case *logging.ConnectionCloseFrame: 56 marshalConnectionCloseFrame(enc, frame) 57 case *logging.HandshakeDoneFrame: 58 marshalHandshakeDoneFrame(enc, frame) 59 case *logging.DatagramFrame: 60 marshalDatagramFrame(enc, frame) 61 default: 62 panic("unknown frame type") 63 } 64 } 65 66 func (f frame) IsNil() bool { return false } 67 68 type frames []frame 69 70 func (fs frames) IsNil() bool { return fs == nil } 71 func (fs frames) MarshalJSONArray(enc *gojay.Encoder) { 72 for _, f := range fs { 73 enc.Object(f) 74 } 75 } 76 77 func marshalPingFrame(enc *gojay.Encoder, _ *wire.PingFrame) { 78 enc.StringKey("frame_type", "ping") 79 } 80 81 type ackRanges []wire.AckRange 82 83 func (ars ackRanges) MarshalJSONArray(enc *gojay.Encoder) { 84 for _, r := range ars { 85 enc.Array(ackRange(r)) 86 } 87 } 88 89 func (ars ackRanges) IsNil() bool { return false } 90 91 type ackRange wire.AckRange 92 93 func (ar ackRange) MarshalJSONArray(enc *gojay.Encoder) { 94 enc.AddInt64(int64(ar.Smallest)) 95 if ar.Smallest != ar.Largest { 96 enc.AddInt64(int64(ar.Largest)) 97 } 98 } 99 100 func (ar ackRange) IsNil() bool { return false } 101 102 func marshalAckFrame(enc *gojay.Encoder, f *logging.AckFrame) { 103 enc.StringKey("frame_type", "ack") 104 enc.FloatKeyOmitEmpty("ack_delay", milliseconds(f.DelayTime)) 105 enc.ArrayKey("acked_ranges", ackRanges(f.AckRanges)) 106 if hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0; hasECN { 107 enc.Uint64Key("ect0", f.ECT0) 108 enc.Uint64Key("ect1", f.ECT1) 109 enc.Uint64Key("ce", f.ECNCE) 110 } 111 } 112 113 func marshalResetStreamFrame(enc *gojay.Encoder, f *logging.ResetStreamFrame) { 114 enc.StringKey("frame_type", "reset_stream") 115 enc.Int64Key("stream_id", int64(f.StreamID)) 116 enc.Int64Key("error_code", int64(f.ErrorCode)) 117 enc.Int64Key("final_size", int64(f.FinalSize)) 118 } 119 120 func marshalStopSendingFrame(enc *gojay.Encoder, f *logging.StopSendingFrame) { 121 enc.StringKey("frame_type", "stop_sending") 122 enc.Int64Key("stream_id", int64(f.StreamID)) 123 enc.Int64Key("error_code", int64(f.ErrorCode)) 124 } 125 126 func marshalCryptoFrame(enc *gojay.Encoder, f *logging.CryptoFrame) { 127 enc.StringKey("frame_type", "crypto") 128 enc.Int64Key("offset", int64(f.Offset)) 129 enc.Int64Key("length", int64(f.Length)) 130 } 131 132 func marshalNewTokenFrame(enc *gojay.Encoder, f *logging.NewTokenFrame) { 133 enc.StringKey("frame_type", "new_token") 134 enc.ObjectKey("token", &token{Raw: f.Token}) 135 } 136 137 func marshalStreamFrame(enc *gojay.Encoder, f *logging.StreamFrame) { 138 enc.StringKey("frame_type", "stream") 139 enc.Int64Key("stream_id", int64(f.StreamID)) 140 enc.Int64Key("offset", int64(f.Offset)) 141 enc.IntKey("length", int(f.Length)) 142 enc.BoolKeyOmitEmpty("fin", f.Fin) 143 } 144 145 func marshalMaxDataFrame(enc *gojay.Encoder, f *logging.MaxDataFrame) { 146 enc.StringKey("frame_type", "max_data") 147 enc.Int64Key("maximum", int64(f.MaximumData)) 148 } 149 150 func marshalMaxStreamDataFrame(enc *gojay.Encoder, f *logging.MaxStreamDataFrame) { 151 enc.StringKey("frame_type", "max_stream_data") 152 enc.Int64Key("stream_id", int64(f.StreamID)) 153 enc.Int64Key("maximum", int64(f.MaximumStreamData)) 154 } 155 156 func marshalMaxStreamsFrame(enc *gojay.Encoder, f *logging.MaxStreamsFrame) { 157 enc.StringKey("frame_type", "max_streams") 158 enc.StringKey("stream_type", streamType(f.Type).String()) 159 enc.Int64Key("maximum", int64(f.MaxStreamNum)) 160 } 161 162 func marshalDataBlockedFrame(enc *gojay.Encoder, f *logging.DataBlockedFrame) { 163 enc.StringKey("frame_type", "data_blocked") 164 enc.Int64Key("limit", int64(f.MaximumData)) 165 } 166 167 func marshalStreamDataBlockedFrame(enc *gojay.Encoder, f *logging.StreamDataBlockedFrame) { 168 enc.StringKey("frame_type", "stream_data_blocked") 169 enc.Int64Key("stream_id", int64(f.StreamID)) 170 enc.Int64Key("limit", int64(f.MaximumStreamData)) 171 } 172 173 func marshalStreamsBlockedFrame(enc *gojay.Encoder, f *logging.StreamsBlockedFrame) { 174 enc.StringKey("frame_type", "streams_blocked") 175 enc.StringKey("stream_type", streamType(f.Type).String()) 176 enc.Int64Key("limit", int64(f.StreamLimit)) 177 } 178 179 func marshalNewConnectionIDFrame(enc *gojay.Encoder, f *logging.NewConnectionIDFrame) { 180 enc.StringKey("frame_type", "new_connection_id") 181 enc.Int64Key("sequence_number", int64(f.SequenceNumber)) 182 enc.Int64Key("retire_prior_to", int64(f.RetirePriorTo)) 183 enc.IntKey("length", f.ConnectionID.Len()) 184 enc.StringKey("connection_id", f.ConnectionID.String()) 185 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", f.StatelessResetToken)) 186 } 187 188 func marshalRetireConnectionIDFrame(enc *gojay.Encoder, f *logging.RetireConnectionIDFrame) { 189 enc.StringKey("frame_type", "retire_connection_id") 190 enc.Int64Key("sequence_number", int64(f.SequenceNumber)) 191 } 192 193 func marshalPathChallengeFrame(enc *gojay.Encoder, f *logging.PathChallengeFrame) { 194 enc.StringKey("frame_type", "path_challenge") 195 enc.StringKey("data", fmt.Sprintf("%x", f.Data[:])) 196 } 197 198 func marshalPathResponseFrame(enc *gojay.Encoder, f *logging.PathResponseFrame) { 199 enc.StringKey("frame_type", "path_response") 200 enc.StringKey("data", fmt.Sprintf("%x", f.Data[:])) 201 } 202 203 func marshalConnectionCloseFrame(enc *gojay.Encoder, f *logging.ConnectionCloseFrame) { 204 errorSpace := "transport" 205 if f.IsApplicationError { 206 errorSpace = "application" 207 } 208 enc.StringKey("frame_type", "connection_close") 209 enc.StringKey("error_space", errorSpace) 210 if errName := transportError(f.ErrorCode).String(); len(errName) > 0 { 211 enc.StringKey("error_code", errName) 212 } else { 213 enc.Uint64Key("error_code", f.ErrorCode) 214 } 215 enc.Uint64Key("raw_error_code", f.ErrorCode) 216 enc.StringKey("reason", f.ReasonPhrase) 217 } 218 219 func marshalHandshakeDoneFrame(enc *gojay.Encoder, _ *logging.HandshakeDoneFrame) { 220 enc.StringKey("frame_type", "handshake_done") 221 } 222 223 func marshalDatagramFrame(enc *gojay.Encoder, f *logging.DatagramFrame) { 224 enc.StringKey("frame_type", "datagram") 225 enc.Int64Key("length", int64(f.Length)) 226 }