github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/qlog/connection_tracer.go (about)

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