github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/qlog/connection_tracer.go (about)

     1  package qlog
     2  
     3  import (
     4  	"io"
     5  	"net"
     6  	"time"
     7  
     8  	"github.com/metacubex/quic-go/internal/protocol"
     9  	"github.com/metacubex/quic-go/internal/utils"
    10  	"github.com/metacubex/quic-go/internal/wire"
    11  	"github.com/metacubex/quic-go/logging"
    12  
    13  	"github.com/francoispqt/gojay"
    14  )
    15  
    16  type connectionTracer struct {
    17  	w           writer
    18  	lastMetrics *metrics
    19  
    20  	perspective logging.Perspective
    21  }
    22  
    23  // NewConnectionTracer creates a new tracer to record a qlog for a connection.
    24  func NewConnectionTracer(w io.WriteCloser, p logging.Perspective, odcid protocol.ConnectionID) *logging.ConnectionTracer {
    25  	tr := &trace{
    26  		VantagePoint: vantagePoint{Type: p.String()},
    27  		CommonFields: commonFields{
    28  			ODCID:         &odcid,
    29  			GroupID:       &odcid,
    30  			ReferenceTime: time.Now(),
    31  		},
    32  	}
    33  	t := connectionTracer{
    34  		w:           *newWriter(w, tr),
    35  		perspective: p,
    36  	}
    37  	go t.w.Run()
    38  	return &logging.ConnectionTracer{
    39  		StartedConnection: func(local, remote net.Addr, srcConnID, destConnID logging.ConnectionID) {
    40  			t.StartedConnection(local, remote, srcConnID, destConnID)
    41  		},
    42  		NegotiatedVersion: func(chosen logging.VersionNumber, clientVersions, serverVersions []logging.VersionNumber) {
    43  			t.NegotiatedVersion(chosen, clientVersions, serverVersions)
    44  		},
    45  		ClosedConnection:            func(e error) { t.ClosedConnection(e) },
    46  		SentTransportParameters:     func(tp *wire.TransportParameters) { t.SentTransportParameters(tp) },
    47  		ReceivedTransportParameters: func(tp *wire.TransportParameters) { t.ReceivedTransportParameters(tp) },
    48  		RestoredTransportParameters: func(tp *wire.TransportParameters) { t.RestoredTransportParameters(tp) },
    49  		SentLongHeaderPacket: func(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
    50  			t.SentLongHeaderPacket(hdr, size, ecn, ack, frames)
    51  		},
    52  		SentShortHeaderPacket: func(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, ack *logging.AckFrame, frames []logging.Frame) {
    53  			t.SentShortHeaderPacket(hdr, size, ecn, ack, frames)
    54  		},
    55  		ReceivedLongHeaderPacket: func(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
    56  			t.ReceivedLongHeaderPacket(hdr, size, ecn, frames)
    57  		},
    58  		ReceivedShortHeaderPacket: func(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
    59  			t.ReceivedShortHeaderPacket(hdr, size, ecn, frames)
    60  		},
    61  		ReceivedRetry: func(hdr *wire.Header) {
    62  			t.ReceivedRetry(hdr)
    63  		},
    64  		ReceivedVersionNegotiationPacket: func(dest, src logging.ArbitraryLenConnectionID, versions []logging.VersionNumber) {
    65  			t.ReceivedVersionNegotiationPacket(dest, src, versions)
    66  		},
    67  		BufferedPacket: func(pt logging.PacketType, size protocol.ByteCount) {
    68  			t.BufferedPacket(pt, size)
    69  		},
    70  		DroppedPacket: func(pt logging.PacketType, pn logging.PacketNumber, size logging.ByteCount, reason logging.PacketDropReason) {
    71  			t.DroppedPacket(pt, pn, size, reason)
    72  		},
    73  		UpdatedMetrics: func(rttStats *utils.RTTStats, cwnd, bytesInFlight protocol.ByteCount, packetsInFlight int) {
    74  			t.UpdatedMetrics(rttStats, cwnd, bytesInFlight, packetsInFlight)
    75  		},
    76  		LostPacket: func(encLevel protocol.EncryptionLevel, pn protocol.PacketNumber, lossReason logging.PacketLossReason) {
    77  			t.LostPacket(encLevel, pn, lossReason)
    78  		},
    79  		UpdatedMTU: func(mtu logging.ByteCount, done bool) {
    80  			t.UpdatedMTU(mtu, done)
    81  		},
    82  		UpdatedCongestionState: func(state logging.CongestionState) {
    83  			t.UpdatedCongestionState(state)
    84  		},
    85  		UpdatedPTOCount: func(value uint32) {
    86  			t.UpdatedPTOCount(value)
    87  		},
    88  		UpdatedKeyFromTLS: func(encLevel protocol.EncryptionLevel, pers protocol.Perspective) {
    89  			t.UpdatedKeyFromTLS(encLevel, pers)
    90  		},
    91  		UpdatedKey: func(keyPhase protocol.KeyPhase, remote bool) {
    92  			t.UpdatedKey(keyPhase, remote)
    93  		},
    94  		DroppedEncryptionLevel: func(encLevel protocol.EncryptionLevel) {
    95  			t.DroppedEncryptionLevel(encLevel)
    96  		},
    97  		DroppedKey: func(keyPhase protocol.KeyPhase) {
    98  			t.DroppedKey(keyPhase)
    99  		},
   100  		SetLossTimer: func(tt logging.TimerType, encLevel protocol.EncryptionLevel, timeout time.Time) {
   101  			t.SetLossTimer(tt, encLevel, timeout)
   102  		},
   103  		LossTimerExpired: func(tt logging.TimerType, encLevel protocol.EncryptionLevel) {
   104  			t.LossTimerExpired(tt, encLevel)
   105  		},
   106  		LossTimerCanceled: func() {
   107  			t.LossTimerCanceled()
   108  		},
   109  		ECNStateUpdated: func(state logging.ECNState, trigger logging.ECNStateTrigger) {
   110  			t.ECNStateUpdated(state, trigger)
   111  		},
   112  		ChoseALPN: func(protocol string) {
   113  			t.recordEvent(time.Now(), eventALPNInformation{chosenALPN: protocol})
   114  		},
   115  		Debug: func(name, msg string) {
   116  			t.Debug(name, msg)
   117  		},
   118  		Close: func() {
   119  			t.Close()
   120  		},
   121  	}
   122  }
   123  
   124  func (t *connectionTracer) recordEvent(eventTime time.Time, details eventDetails) {
   125  	t.w.RecordEvent(eventTime, details)
   126  }
   127  
   128  func (t *connectionTracer) Close() {
   129  	t.w.Close()
   130  }
   131  
   132  func (t *connectionTracer) StartedConnection(local, remote net.Addr, srcConnID, destConnID protocol.ConnectionID) {
   133  	// ignore this event if we're not dealing with UDP addresses here
   134  	localAddr, ok := local.(*net.UDPAddr)
   135  	if !ok {
   136  		return
   137  	}
   138  	remoteAddr, ok := remote.(*net.UDPAddr)
   139  	if !ok {
   140  		return
   141  	}
   142  	t.recordEvent(time.Now(), &eventConnectionStarted{
   143  		SrcAddr:          localAddr,
   144  		DestAddr:         remoteAddr,
   145  		SrcConnectionID:  srcConnID,
   146  		DestConnectionID: destConnID,
   147  	})
   148  }
   149  
   150  func (t *connectionTracer) NegotiatedVersion(chosen logging.VersionNumber, client, server []logging.VersionNumber) {
   151  	var clientVersions, serverVersions []versionNumber
   152  	if len(client) > 0 {
   153  		clientVersions = make([]versionNumber, len(client))
   154  		for i, v := range client {
   155  			clientVersions[i] = versionNumber(v)
   156  		}
   157  	}
   158  	if len(server) > 0 {
   159  		serverVersions = make([]versionNumber, len(server))
   160  		for i, v := range server {
   161  			serverVersions[i] = versionNumber(v)
   162  		}
   163  	}
   164  	t.recordEvent(time.Now(), &eventVersionNegotiated{
   165  		clientVersions: clientVersions,
   166  		serverVersions: serverVersions,
   167  		chosenVersion:  versionNumber(chosen),
   168  	})
   169  }
   170  
   171  func (t *connectionTracer) ClosedConnection(e error) {
   172  	t.recordEvent(time.Now(), &eventConnectionClosed{e: e})
   173  }
   174  
   175  func (t *connectionTracer) SentTransportParameters(tp *wire.TransportParameters) {
   176  	t.recordTransportParameters(t.perspective, tp)
   177  }
   178  
   179  func (t *connectionTracer) ReceivedTransportParameters(tp *wire.TransportParameters) {
   180  	t.recordTransportParameters(t.perspective.Opposite(), tp)
   181  }
   182  
   183  func (t *connectionTracer) RestoredTransportParameters(tp *wire.TransportParameters) {
   184  	ev := t.toTransportParameters(tp)
   185  	ev.Restore = true
   186  
   187  	t.recordEvent(time.Now(), ev)
   188  }
   189  
   190  func (t *connectionTracer) recordTransportParameters(sentBy protocol.Perspective, tp *wire.TransportParameters) {
   191  	ev := t.toTransportParameters(tp)
   192  	ev.Owner = ownerLocal
   193  	if sentBy != t.perspective {
   194  		ev.Owner = ownerRemote
   195  	}
   196  	ev.SentBy = sentBy
   197  
   198  	t.recordEvent(time.Now(), ev)
   199  }
   200  
   201  func (t *connectionTracer) toTransportParameters(tp *wire.TransportParameters) *eventTransportParameters {
   202  	var pa *preferredAddress
   203  	if tp.PreferredAddress != nil {
   204  		pa = &preferredAddress{
   205  			IPv4:                tp.PreferredAddress.IPv4,
   206  			IPv6:                tp.PreferredAddress.IPv6,
   207  			ConnectionID:        tp.PreferredAddress.ConnectionID,
   208  			StatelessResetToken: tp.PreferredAddress.StatelessResetToken,
   209  		}
   210  	}
   211  	return &eventTransportParameters{
   212  		OriginalDestinationConnectionID: tp.OriginalDestinationConnectionID,
   213  		InitialSourceConnectionID:       tp.InitialSourceConnectionID,
   214  		RetrySourceConnectionID:         tp.RetrySourceConnectionID,
   215  		StatelessResetToken:             tp.StatelessResetToken,
   216  		DisableActiveMigration:          tp.DisableActiveMigration,
   217  		MaxIdleTimeout:                  tp.MaxIdleTimeout,
   218  		MaxUDPPayloadSize:               tp.MaxUDPPayloadSize,
   219  		AckDelayExponent:                tp.AckDelayExponent,
   220  		MaxAckDelay:                     tp.MaxAckDelay,
   221  		ActiveConnectionIDLimit:         tp.ActiveConnectionIDLimit,
   222  		InitialMaxData:                  tp.InitialMaxData,
   223  		InitialMaxStreamDataBidiLocal:   tp.InitialMaxStreamDataBidiLocal,
   224  		InitialMaxStreamDataBidiRemote:  tp.InitialMaxStreamDataBidiRemote,
   225  		InitialMaxStreamDataUni:         tp.InitialMaxStreamDataUni,
   226  		InitialMaxStreamsBidi:           int64(tp.MaxBidiStreamNum),
   227  		InitialMaxStreamsUni:            int64(tp.MaxUniStreamNum),
   228  		PreferredAddress:                pa,
   229  		MaxDatagramFrameSize:            tp.MaxDatagramFrameSize,
   230  	}
   231  }
   232  
   233  func (t *connectionTracer) SentLongHeaderPacket(
   234  	hdr *logging.ExtendedHeader,
   235  	size logging.ByteCount,
   236  	ecn logging.ECN,
   237  	ack *logging.AckFrame,
   238  	frames []logging.Frame,
   239  ) {
   240  	t.sentPacket(*transformLongHeader(hdr), size, hdr.Length, ecn, ack, frames)
   241  }
   242  
   243  func (t *connectionTracer) SentShortHeaderPacket(
   244  	hdr *logging.ShortHeader,
   245  	size logging.ByteCount,
   246  	ecn logging.ECN,
   247  	ack *logging.AckFrame,
   248  	frames []logging.Frame,
   249  ) {
   250  	t.sentPacket(*transformShortHeader(hdr), size, 0, ecn, ack, frames)
   251  }
   252  
   253  func (t *connectionTracer) sentPacket(
   254  	hdr gojay.MarshalerJSONObject,
   255  	size, payloadLen logging.ByteCount,
   256  	ecn logging.ECN,
   257  	ack *logging.AckFrame,
   258  	frames []logging.Frame,
   259  ) {
   260  	numFrames := len(frames)
   261  	if ack != nil {
   262  		numFrames++
   263  	}
   264  	fs := make([]frame, 0, numFrames)
   265  	if ack != nil {
   266  		fs = append(fs, frame{Frame: ack})
   267  	}
   268  	for _, f := range frames {
   269  		fs = append(fs, frame{Frame: f})
   270  	}
   271  	t.recordEvent(time.Now(), &eventPacketSent{
   272  		Header:        hdr,
   273  		Length:        size,
   274  		PayloadLength: payloadLen,
   275  		ECN:           ecn,
   276  		Frames:        fs,
   277  	})
   278  }
   279  
   280  func (t *connectionTracer) ReceivedLongHeaderPacket(hdr *logging.ExtendedHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
   281  	fs := make([]frame, len(frames))
   282  	for i, f := range frames {
   283  		fs[i] = frame{Frame: f}
   284  	}
   285  	header := *transformLongHeader(hdr)
   286  	t.recordEvent(time.Now(), &eventPacketReceived{
   287  		Header:        header,
   288  		Length:        size,
   289  		PayloadLength: hdr.Length,
   290  		ECN:           ecn,
   291  		Frames:        fs,
   292  	})
   293  }
   294  
   295  func (t *connectionTracer) ReceivedShortHeaderPacket(hdr *logging.ShortHeader, size logging.ByteCount, ecn logging.ECN, frames []logging.Frame) {
   296  	fs := make([]frame, len(frames))
   297  	for i, f := range frames {
   298  		fs[i] = frame{Frame: f}
   299  	}
   300  	header := *transformShortHeader(hdr)
   301  	t.recordEvent(time.Now(), &eventPacketReceived{
   302  		Header:        header,
   303  		Length:        size,
   304  		PayloadLength: size - wire.ShortHeaderLen(hdr.DestConnectionID, hdr.PacketNumberLen),
   305  		ECN:           ecn,
   306  		Frames:        fs,
   307  	})
   308  }
   309  
   310  func (t *connectionTracer) ReceivedRetry(hdr *wire.Header) {
   311  	t.recordEvent(time.Now(), &eventRetryReceived{
   312  		Header: *transformHeader(hdr),
   313  	})
   314  }
   315  
   316  func (t *connectionTracer) ReceivedVersionNegotiationPacket(dest, src logging.ArbitraryLenConnectionID, versions []logging.VersionNumber) {
   317  	ver := make([]versionNumber, len(versions))
   318  	for i, v := range versions {
   319  		ver[i] = versionNumber(v)
   320  	}
   321  	t.recordEvent(time.Now(), &eventVersionNegotiationReceived{
   322  		Header: packetHeaderVersionNegotiation{
   323  			SrcConnectionID:  src,
   324  			DestConnectionID: dest,
   325  		},
   326  		SupportedVersions: ver,
   327  	})
   328  }
   329  
   330  func (t *connectionTracer) BufferedPacket(pt logging.PacketType, size protocol.ByteCount) {
   331  	t.recordEvent(time.Now(), &eventPacketBuffered{
   332  		PacketType: pt,
   333  		PacketSize: size,
   334  	})
   335  }
   336  
   337  func (t *connectionTracer) DroppedPacket(pt logging.PacketType, pn logging.PacketNumber, size protocol.ByteCount, reason logging.PacketDropReason) {
   338  	t.recordEvent(time.Now(), &eventPacketDropped{
   339  		PacketType:   pt,
   340  		PacketNumber: pn,
   341  		PacketSize:   size,
   342  		Trigger:      packetDropReason(reason),
   343  	})
   344  }
   345  
   346  func (t *connectionTracer) UpdatedMetrics(rttStats *utils.RTTStats, cwnd, bytesInFlight protocol.ByteCount, packetsInFlight int) {
   347  	m := &metrics{
   348  		MinRTT:           rttStats.MinRTT(),
   349  		SmoothedRTT:      rttStats.SmoothedRTT(),
   350  		LatestRTT:        rttStats.LatestRTT(),
   351  		RTTVariance:      rttStats.MeanDeviation(),
   352  		CongestionWindow: cwnd,
   353  		BytesInFlight:    bytesInFlight,
   354  		PacketsInFlight:  packetsInFlight,
   355  	}
   356  	t.recordEvent(time.Now(), &eventMetricsUpdated{
   357  		Last:    t.lastMetrics,
   358  		Current: m,
   359  	})
   360  	t.lastMetrics = m
   361  }
   362  
   363  func (t *connectionTracer) AcknowledgedPacket(protocol.EncryptionLevel, protocol.PacketNumber) {}
   364  
   365  func (t *connectionTracer) LostPacket(encLevel protocol.EncryptionLevel, pn protocol.PacketNumber, lossReason logging.PacketLossReason) {
   366  	t.recordEvent(time.Now(), &eventPacketLost{
   367  		PacketType:   getPacketTypeFromEncryptionLevel(encLevel),
   368  		PacketNumber: pn,
   369  		Trigger:      packetLossReason(lossReason),
   370  	})
   371  }
   372  
   373  func (t *connectionTracer) UpdatedMTU(mtu protocol.ByteCount, done bool) {
   374  	t.recordEvent(time.Now(), &eventMTUUpdated{mtu: mtu, done: done})
   375  }
   376  
   377  func (t *connectionTracer) UpdatedCongestionState(state logging.CongestionState) {
   378  	t.recordEvent(time.Now(), &eventCongestionStateUpdated{state: congestionState(state)})
   379  }
   380  
   381  func (t *connectionTracer) UpdatedPTOCount(value uint32) {
   382  	t.recordEvent(time.Now(), &eventUpdatedPTO{Value: value})
   383  }
   384  
   385  func (t *connectionTracer) UpdatedKeyFromTLS(encLevel protocol.EncryptionLevel, pers protocol.Perspective) {
   386  	t.recordEvent(time.Now(), &eventKeyUpdated{
   387  		Trigger: keyUpdateTLS,
   388  		KeyType: encLevelToKeyType(encLevel, pers),
   389  	})
   390  }
   391  
   392  func (t *connectionTracer) UpdatedKey(generation protocol.KeyPhase, remote bool) {
   393  	trigger := keyUpdateLocal
   394  	if remote {
   395  		trigger = keyUpdateRemote
   396  	}
   397  	now := time.Now()
   398  	t.recordEvent(now, &eventKeyUpdated{
   399  		Trigger:  trigger,
   400  		KeyType:  keyTypeClient1RTT,
   401  		KeyPhase: generation,
   402  	})
   403  	t.recordEvent(now, &eventKeyUpdated{
   404  		Trigger:  trigger,
   405  		KeyType:  keyTypeServer1RTT,
   406  		KeyPhase: generation,
   407  	})
   408  }
   409  
   410  func (t *connectionTracer) DroppedEncryptionLevel(encLevel protocol.EncryptionLevel) {
   411  	now := time.Now()
   412  	if encLevel == protocol.Encryption0RTT {
   413  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, t.perspective)})
   414  	} else {
   415  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveServer)})
   416  		t.recordEvent(now, &eventKeyDiscarded{KeyType: encLevelToKeyType(encLevel, protocol.PerspectiveClient)})
   417  	}
   418  }
   419  
   420  func (t *connectionTracer) DroppedKey(generation protocol.KeyPhase) {
   421  	now := time.Now()
   422  	t.recordEvent(now, &eventKeyDiscarded{
   423  		KeyType:  encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveServer),
   424  		KeyPhase: generation,
   425  	})
   426  	t.recordEvent(now, &eventKeyDiscarded{
   427  		KeyType:  encLevelToKeyType(protocol.Encryption1RTT, protocol.PerspectiveClient),
   428  		KeyPhase: generation,
   429  	})
   430  }
   431  
   432  func (t *connectionTracer) SetLossTimer(tt logging.TimerType, encLevel protocol.EncryptionLevel, timeout time.Time) {
   433  	now := time.Now()
   434  	t.recordEvent(now, &eventLossTimerSet{
   435  		TimerType: timerType(tt),
   436  		EncLevel:  encLevel,
   437  		Delta:     timeout.Sub(now),
   438  	})
   439  }
   440  
   441  func (t *connectionTracer) LossTimerExpired(tt logging.TimerType, encLevel protocol.EncryptionLevel) {
   442  	t.recordEvent(time.Now(), &eventLossTimerExpired{
   443  		TimerType: timerType(tt),
   444  		EncLevel:  encLevel,
   445  	})
   446  }
   447  
   448  func (t *connectionTracer) LossTimerCanceled() {
   449  	t.recordEvent(time.Now(), &eventLossTimerCanceled{})
   450  }
   451  
   452  func (t *connectionTracer) ECNStateUpdated(state logging.ECNState, trigger logging.ECNStateTrigger) {
   453  	t.recordEvent(time.Now(), &eventECNStateUpdated{state: state, trigger: trigger})
   454  }
   455  
   456  func (t *connectionTracer) Debug(name, msg string) {
   457  	t.recordEvent(time.Now(), &eventGeneric{
   458  		name: name,
   459  		msg:  msg,
   460  	})
   461  }