1package qlog 2 3import ( 4 "fmt" 5 6 "github.com/lucas-clemente/quic-go/internal/wire" 7 "github.com/lucas-clemente/quic-go/logging" 8 9 "github.com/francoispqt/gojay" 10) 11 12type frame struct { 13 Frame logging.Frame 14} 15 16var _ gojay.MarshalerJSONObject = frame{} 17 18var _ gojay.MarshalerJSONArray = frames{} 19 20func (f frame) MarshalJSONObject(enc *gojay.Encoder) { 21 switch frame := f.Frame.(type) { 22 case *logging.PingFrame: 23 marshalPingFrame(enc, frame) 24 case *logging.AckFrame: 25 marshalAckFrame(enc, frame) 26 case *logging.ResetStreamFrame: 27 marshalResetStreamFrame(enc, frame) 28 case *logging.StopSendingFrame: 29 marshalStopSendingFrame(enc, frame) 30 case *logging.CryptoFrame: 31 marshalCryptoFrame(enc, frame) 32 case *logging.NewTokenFrame: 33 marshalNewTokenFrame(enc, frame) 34 case *logging.StreamFrame: 35 marshalStreamFrame(enc, frame) 36 case *logging.MaxDataFrame: 37 marshalMaxDataFrame(enc, frame) 38 case *logging.MaxStreamDataFrame: 39 marshalMaxStreamDataFrame(enc, frame) 40 case *logging.MaxStreamsFrame: 41 marshalMaxStreamsFrame(enc, frame) 42 case *logging.DataBlockedFrame: 43 marshalDataBlockedFrame(enc, frame) 44 case *logging.StreamDataBlockedFrame: 45 marshalStreamDataBlockedFrame(enc, frame) 46 case *logging.StreamsBlockedFrame: 47 marshalStreamsBlockedFrame(enc, frame) 48 case *logging.NewConnectionIDFrame: 49 marshalNewConnectionIDFrame(enc, frame) 50 case *logging.RetireConnectionIDFrame: 51 marshalRetireConnectionIDFrame(enc, frame) 52 case *logging.PathChallengeFrame: 53 marshalPathChallengeFrame(enc, frame) 54 case *logging.PathResponseFrame: 55 marshalPathResponseFrame(enc, frame) 56 case *logging.ConnectionCloseFrame: 57 marshalConnectionCloseFrame(enc, frame) 58 case *logging.HandshakeDoneFrame: 59 marshalHandshakeDoneFrame(enc, frame) 60 default: 61 panic("unknown frame type") 62 } 63} 64 65func (f frame) IsNil() bool { return false } 66 67type frames []frame 68 69func (fs frames) IsNil() bool { return fs == nil } 70func (fs frames) MarshalJSONArray(enc *gojay.Encoder) { 71 for _, f := range fs { 72 enc.Object(f) 73 } 74} 75 76func marshalPingFrame(enc *gojay.Encoder, _ *wire.PingFrame) { 77 enc.StringKey("frame_type", "ping") 78} 79 80type ackRanges []wire.AckRange 81 82func (ars ackRanges) MarshalJSONArray(enc *gojay.Encoder) { 83 for _, r := range ars { 84 enc.Array(ackRange(r)) 85 } 86} 87 88func (ars ackRanges) IsNil() bool { return false } 89 90type ackRange wire.AckRange 91 92func (ar ackRange) MarshalJSONArray(enc *gojay.Encoder) { 93 enc.AddInt64(int64(ar.Smallest)) 94 if ar.Smallest != ar.Largest { 95 enc.AddInt64(int64(ar.Largest)) 96 } 97} 98 99func (ar ackRange) IsNil() bool { return false } 100 101func marshalAckFrame(enc *gojay.Encoder, f *logging.AckFrame) { 102 enc.StringKey("frame_type", "ack") 103 enc.FloatKeyOmitEmpty("ack_delay", milliseconds(f.DelayTime)) 104 enc.ArrayKey("acked_ranges", ackRanges(f.AckRanges)) 105 if hasECN := f.ECT0 > 0 || f.ECT1 > 0 || f.ECNCE > 0; hasECN { 106 enc.Uint64Key("ect0", f.ECT0) 107 enc.Uint64Key("ect1", f.ECT1) 108 enc.Uint64Key("ce", f.ECNCE) 109 } 110} 111 112func marshalResetStreamFrame(enc *gojay.Encoder, f *logging.ResetStreamFrame) { 113 enc.StringKey("frame_type", "reset_stream") 114 enc.Int64Key("stream_id", int64(f.StreamID)) 115 enc.Int64Key("error_code", int64(f.ErrorCode)) 116 enc.Int64Key("final_size", int64(f.FinalSize)) 117} 118 119func marshalStopSendingFrame(enc *gojay.Encoder, f *logging.StopSendingFrame) { 120 enc.StringKey("frame_type", "stop_sending") 121 enc.Int64Key("stream_id", int64(f.StreamID)) 122 enc.Int64Key("error_code", int64(f.ErrorCode)) 123} 124 125func marshalCryptoFrame(enc *gojay.Encoder, f *logging.CryptoFrame) { 126 enc.StringKey("frame_type", "crypto") 127 enc.Int64Key("offset", int64(f.Offset)) 128 enc.Int64Key("length", int64(f.Length)) 129} 130 131func marshalNewTokenFrame(enc *gojay.Encoder, f *logging.NewTokenFrame) { 132 enc.StringKey("frame_type", "new_token") 133 enc.IntKey("length", len(f.Token)) 134 enc.StringKey("token", fmt.Sprintf("%x", f.Token)) 135} 136 137func 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 145func marshalMaxDataFrame(enc *gojay.Encoder, f *logging.MaxDataFrame) { 146 enc.StringKey("frame_type", "max_data") 147 enc.Int64Key("maximum", int64(f.MaximumData)) 148} 149 150func 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 156func 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 162func marshalDataBlockedFrame(enc *gojay.Encoder, f *logging.DataBlockedFrame) { 163 enc.StringKey("frame_type", "data_blocked") 164 enc.Int64Key("limit", int64(f.MaximumData)) 165} 166 167func 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 173func 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 179func 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", connectionID(f.ConnectionID).String()) 185 enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", f.StatelessResetToken)) 186} 187 188func 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 193func 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 198func 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 203func 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", uint64(f.ErrorCode)) 214 } 215 enc.Uint64Key("raw_error_code", uint64(f.ErrorCode)) 216 enc.StringKey("reason", f.ReasonPhrase) 217} 218 219func marshalHandshakeDoneFrame(enc *gojay.Encoder, _ *logging.HandshakeDoneFrame) { 220 enc.StringKey("frame_type", "handshake_done") 221} 222