github.com/sagernet/quic-go@v0.43.1-beta.1/qlog/connection_tracer.go (about)

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