From 4372f46345b0bb365ec8e221d9295aad17eb22c2 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Mon, 2 Nov 2020 12:31:17 +0700 Subject: [PATCH] implement qlogging of the preferred address in the transport parameters --- logging/interface.go | 2 ++ qlog/event.go | 25 ++++++++++++++++++++++++- qlog/qlog.go | 12 ++++++++++++ qlog/qlog_test.go | 28 ++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/logging/interface.go b/logging/interface.go index b0c41fb8..e1baeb72 100644 --- a/logging/interface.go +++ b/logging/interface.go @@ -45,6 +45,8 @@ type ( ExtendedHeader = wire.ExtendedHeader // The TransportParameters are QUIC transport parameters. TransportParameters = wire.TransportParameters + // The PreferredAddress is the preferred address sent in the transport parameters. + PreferredAddress = wire.PreferredAddress // A TransportError is a transport-level error code. TransportError = qerr.ErrorCode diff --git a/qlog/event.go b/qlog/event.go index f06c99ee..2c6ca814 100644 --- a/qlog/event.go +++ b/qlog/event.go @@ -352,7 +352,7 @@ type eventTransportParameters struct { InitialMaxStreamsBidi int64 InitialMaxStreamsUni int64 - // TODO: add the preferred_address + PreferredAddress *preferredAddress } func (e eventTransportParameters) Category() category { return categoryTransport } @@ -384,6 +384,29 @@ func (e eventTransportParameters) MarshalJSONObject(enc *gojay.Encoder) { enc.Int64KeyOmitEmpty("initial_max_stream_data_uni", int64(e.InitialMaxStreamDataUni)) enc.Int64KeyOmitEmpty("initial_max_streams_bidi", e.InitialMaxStreamsBidi) enc.Int64KeyOmitEmpty("initial_max_streams_uni", e.InitialMaxStreamsUni) + + if e.PreferredAddress != nil { + enc.ObjectKey("preferred_address", e.PreferredAddress) + } +} + +type preferredAddress struct { + IPv4, IPv6 net.IP + PortV4, PortV6 uint16 + ConnectionID protocol.ConnectionID + StatelessResetToken protocol.StatelessResetToken +} + +var _ gojay.MarshalerJSONObject = &preferredAddress{} + +func (a preferredAddress) IsNil() bool { return false } +func (a preferredAddress) MarshalJSONObject(enc *gojay.Encoder) { + enc.StringKey("ip_v4", a.IPv4.String()) + enc.Uint16Key("port_v4", a.PortV4) + enc.StringKey("ip_v6", a.IPv6.String()) + enc.Uint16Key("port_v6", a.PortV6) + enc.StringKey("connection_id", connectionID(a.ConnectionID).String()) + enc.StringKey("stateless_reset_token", fmt.Sprintf("%x", a.StatelessResetToken)) } type eventLossTimerSet struct { diff --git a/qlog/qlog.go b/qlog/qlog.go index a394c6bd..8b154eac 100644 --- a/qlog/qlog.go +++ b/qlog/qlog.go @@ -188,6 +188,17 @@ func (t *connectionTracer) recordTransportParameters(sentBy protocol.Perspective if sentBy != t.perspective { owner = ownerRemote } + var pa *preferredAddress + if tp.PreferredAddress != nil { + pa = &preferredAddress{ + IPv4: tp.PreferredAddress.IPv4, + PortV4: tp.PreferredAddress.IPv4Port, + IPv6: tp.PreferredAddress.IPv6, + PortV6: tp.PreferredAddress.IPv6Port, + ConnectionID: tp.PreferredAddress.ConnectionID, + StatelessResetToken: tp.PreferredAddress.StatelessResetToken, + } + } t.mutex.Lock() t.recordEvent(time.Now(), &eventTransportParameters{ Owner: owner, @@ -208,6 +219,7 @@ func (t *connectionTracer) recordTransportParameters(sentBy protocol.Perspective InitialMaxStreamDataUni: tp.InitialMaxStreamDataUni, InitialMaxStreamsBidi: int64(tp.MaxBidiStreamNum), InitialMaxStreamsUni: int64(tp.MaxUniStreamNum), + PreferredAddress: pa, }) t.mutex.Unlock() } diff --git a/qlog/qlog_test.go b/qlog/qlog_test.go index b62a07cc..4962826b 100644 --- a/qlog/qlog_test.go +++ b/qlog/qlog_test.go @@ -232,6 +232,7 @@ var _ = Describe("Tracing", func() { Expect(ev).To(HaveKeyWithValue("initial_max_stream_data_uni", float64(3000))) Expect(ev).To(HaveKeyWithValue("initial_max_streams_bidi", float64(10))) Expect(ev).To(HaveKeyWithValue("initial_max_streams_uni", float64(20))) + Expect(ev).ToNot(HaveKey("preferred_address")) }) It("records the server's transport parameters, without a stateless reset token", func() { @@ -260,6 +261,33 @@ var _ = Describe("Tracing", func() { Expect(ev).ToNot(HaveKey("retry_source_connection_id")) }) + It("records transport parameters with a preferred address", func() { + tracer.SentTransportParameters(&logging.TransportParameters{ + PreferredAddress: &logging.PreferredAddress{ + IPv4: net.IPv4(12, 34, 56, 78), + IPv4Port: 123, + IPv6: net.IP{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, + IPv6Port: 456, + ConnectionID: protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}, + StatelessResetToken: protocol.StatelessResetToken{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + }, + }) + entry := exportAndParseSingle() + Expect(entry.Time).To(BeTemporally("~", time.Now(), scaleDuration(10*time.Millisecond))) + Expect(entry.Category).To(Equal("transport")) + Expect(entry.Name).To(Equal("parameters_set")) + ev := entry.Event + Expect(ev).To(HaveKeyWithValue("owner", "local")) + Expect(ev).To(HaveKey("preferred_address")) + pa := ev["preferred_address"].(map[string]interface{}) + Expect(pa).To(HaveKeyWithValue("ip_v4", "12.34.56.78")) + Expect(pa).To(HaveKeyWithValue("port_v4", float64(123))) + Expect(pa).To(HaveKeyWithValue("ip_v6", "102:304:506:708:90a:b0c:d0e:f10")) + Expect(pa).To(HaveKeyWithValue("port_v6", float64(456))) + Expect(pa).To(HaveKeyWithValue("connection_id", "0807060504030201")) + Expect(pa).To(HaveKeyWithValue("stateless_reset_token", "0f0e0d0c0b0a09080706050403020100")) + }) + It("records received transport parameters", func() { tracer.ReceivedTransportParameters(&logging.TransportParameters{}) entry := exportAndParseSingle()