1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_connection_logger.h"
8 #include "base/callback.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/sparse_histogram.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/values.h"
13 #include "net/base/net_log.h"
14 #include "net/quic/crypto/crypto_handshake_message.h"
15 #include "net/quic/crypto/crypto_protocol.h"
16 #include "net/quic/quic_address_mismatch.h"
17 #include "net/quic/quic_socket_address_coder.h"
19 using base::StringPiece
;
26 base::Value
* NetLogQuicPacketCallback(const IPEndPoint
* self_address
,
27 const IPEndPoint
* peer_address
,
29 NetLog::LogLevel
/* log_level */) {
30 base::DictionaryValue
* dict
= new base::DictionaryValue();
31 dict
->SetString("self_address", self_address
->ToString());
32 dict
->SetString("peer_address", peer_address
->ToString());
33 dict
->SetInteger("size", packet_size
);
37 base::Value
* NetLogQuicPacketSentCallback(
38 QuicPacketSequenceNumber sequence_number
,
39 EncryptionLevel level
,
42 NetLog::LogLevel
/* log_level */) {
43 base::DictionaryValue
* dict
= new base::DictionaryValue();
44 dict
->SetInteger("encryption_level", level
);
45 dict
->SetString("packet_sequence_number",
46 base::Uint64ToString(sequence_number
));
47 dict
->SetInteger("size", packet_size
);
48 if (result
.status
!= WRITE_STATUS_OK
) {
49 dict
->SetInteger("net_error", result
.error_code
);
54 base::Value
* NetLogQuicPacketRetransmittedCallback(
55 QuicPacketSequenceNumber old_sequence_number
,
56 QuicPacketSequenceNumber new_sequence_number
,
57 NetLog::LogLevel
/* log_level */) {
58 base::DictionaryValue
* dict
= new base::DictionaryValue();
59 dict
->SetString("old_packet_sequence_number",
60 base::Uint64ToString(old_sequence_number
));
61 dict
->SetString("new_packet_sequence_number",
62 base::Uint64ToString(new_sequence_number
));
66 base::Value
* NetLogQuicPacketHeaderCallback(const QuicPacketHeader
* header
,
67 NetLog::LogLevel
/* log_level */) {
68 base::DictionaryValue
* dict
= new base::DictionaryValue();
69 dict
->SetString("guid",
70 base::Uint64ToString(header
->public_header
.guid
));
71 dict
->SetInteger("reset_flag", header
->public_header
.reset_flag
);
72 dict
->SetInteger("version_flag", header
->public_header
.version_flag
);
73 dict
->SetString("packet_sequence_number",
74 base::Uint64ToString(header
->packet_sequence_number
));
75 dict
->SetInteger("entropy_flag", header
->entropy_flag
);
76 dict
->SetInteger("fec_flag", header
->fec_flag
);
77 dict
->SetInteger("fec_group", header
->fec_group
);
81 base::Value
* NetLogQuicStreamFrameCallback(const QuicStreamFrame
* frame
,
82 NetLog::LogLevel
/* log_level */) {
83 base::DictionaryValue
* dict
= new base::DictionaryValue();
84 dict
->SetInteger("stream_id", frame
->stream_id
);
85 dict
->SetBoolean("fin", frame
->fin
);
86 dict
->SetString("offset", base::Uint64ToString(frame
->offset
));
87 dict
->SetInteger("length", frame
->data
.TotalBufferSize());
91 base::Value
* NetLogQuicAckFrameCallback(const QuicAckFrame
* frame
,
92 NetLog::LogLevel
/* log_level */) {
93 base::DictionaryValue
* dict
= new base::DictionaryValue();
94 base::DictionaryValue
* sent_info
= new base::DictionaryValue();
95 dict
->Set("sent_info", sent_info
);
96 sent_info
->SetString("least_unacked",
97 base::Uint64ToString(frame
->sent_info
.least_unacked
));
98 base::DictionaryValue
* received_info
= new base::DictionaryValue();
99 dict
->Set("received_info", received_info
);
100 received_info
->SetString(
102 base::Uint64ToString(frame
->received_info
.largest_observed
));
103 received_info
->SetBoolean("truncated", frame
->received_info
.is_truncated
);
104 base::ListValue
* missing
= new base::ListValue();
105 received_info
->Set("missing_packets", missing
);
106 const SequenceNumberSet
& missing_packets
=
107 frame
->received_info
.missing_packets
;
108 for (SequenceNumberSet::const_iterator it
= missing_packets
.begin();
109 it
!= missing_packets
.end(); ++it
) {
110 missing
->AppendString(base::Uint64ToString(*it
));
115 base::Value
* NetLogQuicCongestionFeedbackFrameCallback(
116 const QuicCongestionFeedbackFrame
* frame
,
117 NetLog::LogLevel
/* log_level */) {
118 base::DictionaryValue
* dict
= new base::DictionaryValue();
119 switch (frame
->type
) {
120 case kInterArrival
: {
121 dict
->SetString("type", "InterArrival");
122 base::ListValue
* received
= new base::ListValue();
123 dict
->Set("received_packets", received
);
124 for (TimeMap::const_iterator it
=
125 frame
->inter_arrival
.received_packet_times
.begin();
126 it
!= frame
->inter_arrival
.received_packet_times
.end(); ++it
) {
127 std::string value
= base::Uint64ToString(it
->first
) + "@" +
128 base::Uint64ToString(it
->second
.ToDebuggingValue());
129 received
->AppendString(value
);
134 dict
->SetString("type", "FixRate");
135 dict
->SetInteger("bitrate_in_bytes_per_second",
136 frame
->fix_rate
.bitrate
.ToBytesPerSecond());
139 dict
->SetString("type", "TCP");
140 dict
->SetInteger("receive_window", frame
->tcp
.receive_window
);
147 base::Value
* NetLogQuicRstStreamFrameCallback(
148 const QuicRstStreamFrame
* frame
,
149 NetLog::LogLevel
/* log_level */) {
150 base::DictionaryValue
* dict
= new base::DictionaryValue();
151 dict
->SetInteger("stream_id", frame
->stream_id
);
152 dict
->SetInteger("quic_rst_stream_error", frame
->error_code
);
153 dict
->SetString("details", frame
->error_details
);
157 base::Value
* NetLogQuicConnectionCloseFrameCallback(
158 const QuicConnectionCloseFrame
* frame
,
159 NetLog::LogLevel
/* log_level */) {
160 base::DictionaryValue
* dict
= new base::DictionaryValue();
161 dict
->SetInteger("quic_error", frame
->error_code
);
162 dict
->SetString("details", frame
->error_details
);
166 base::Value
* NetLogQuicWindowUpdateFrameCallback(
167 const QuicWindowUpdateFrame
* frame
,
168 NetLog::LogLevel
/* log_level */) {
169 base::DictionaryValue
* dict
= new base::DictionaryValue();
170 dict
->SetInteger("stream_id", frame
->stream_id
);
171 dict
->SetString("byte_offset", base::Uint64ToString(frame
->byte_offset
));
175 base::Value
* NetLogQuicBlockedFrameCallback(
176 const QuicBlockedFrame
* frame
,
177 NetLog::LogLevel
/* log_level */) {
178 base::DictionaryValue
* dict
= new base::DictionaryValue();
179 dict
->SetInteger("stream_id", frame
->stream_id
);
183 base::Value
* NetLogQuicStopWaitingFrameCallback(
184 const QuicStopWaitingFrame
* frame
,
185 NetLog::LogLevel
/* log_level */) {
186 base::DictionaryValue
* dict
= new base::DictionaryValue();
187 base::DictionaryValue
* sent_info
= new base::DictionaryValue();
188 dict
->Set("sent_info", sent_info
);
189 sent_info
->SetString("least_unacked",
190 base::Uint64ToString(frame
->least_unacked
));
194 base::Value
* NetLogQuicVersionNegotiationPacketCallback(
195 const QuicVersionNegotiationPacket
* packet
,
196 NetLog::LogLevel
/* log_level */) {
197 base::DictionaryValue
* dict
= new base::DictionaryValue();
198 base::ListValue
* versions
= new base::ListValue();
199 dict
->Set("versions", versions
);
200 for (QuicVersionVector::const_iterator it
= packet
->versions
.begin();
201 it
!= packet
->versions
.end(); ++it
) {
202 versions
->AppendString(QuicVersionToString(*it
));
207 base::Value
* NetLogQuicCryptoHandshakeMessageCallback(
208 const CryptoHandshakeMessage
* message
,
209 NetLog::LogLevel
/* log_level */) {
210 base::DictionaryValue
* dict
= new base::DictionaryValue();
211 dict
->SetString("quic_crypto_handshake_message", message
->DebugString());
215 base::Value
* NetLogQuicOnConnectionClosedCallback(
218 NetLog::LogLevel
/* log_level */) {
219 base::DictionaryValue
* dict
= new base::DictionaryValue();
220 dict
->SetInteger("quic_error", error
);
221 dict
->SetBoolean("from_peer", from_peer
);
225 void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets
) {
226 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapSent",
227 num_consecutive_missing_packets
);
230 void UpdatePublicResetAddressMismatchHistogram(
231 const IPEndPoint
& server_hello_address
,
232 const IPEndPoint
& public_reset_address
) {
233 int sample
= GetAddressMismatch(server_hello_address
, public_reset_address
);
234 // We are seemingly talking to an older server that does not support the
235 // feature, so we can't report the results in the histogram.
239 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch",
240 sample
, QUIC_ADDRESS_MISMATCH_MAX
);
245 QuicConnectionLogger::QuicConnectionLogger(const BoundNetLog
& net_log
)
247 last_received_packet_sequence_number_(0),
248 largest_received_packet_sequence_number_(0),
249 largest_received_missing_packet_sequence_number_(0),
250 out_of_order_recieved_packet_count_(0),
251 num_truncated_acks_sent_(0),
252 num_truncated_acks_received_(0) {
255 QuicConnectionLogger::~QuicConnectionLogger() {
256 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderPacketsReceived",
257 out_of_order_recieved_packet_count_
);
258 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent",
259 num_truncated_acks_sent_
);
260 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived",
261 num_truncated_acks_received_
);
264 void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame
& frame
) {
265 switch (frame
.type
) {
270 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_SENT
,
271 base::Bind(&NetLogQuicStreamFrameCallback
, frame
.stream_frame
));
275 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_SENT
,
276 base::Bind(&NetLogQuicAckFrameCallback
, frame
.ack_frame
));
277 if (frame
.ack_frame
->received_info
.is_truncated
)
278 ++num_truncated_acks_sent_
;
280 case CONGESTION_FEEDBACK_FRAME
:
282 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_SENT
,
283 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback
,
284 frame
.congestion_feedback_frame
));
286 case RST_STREAM_FRAME
:
287 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient",
288 frame
.rst_stream_frame
->error_code
);
290 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_SENT
,
291 base::Bind(&NetLogQuicRstStreamFrameCallback
,
292 frame
.rst_stream_frame
));
294 case CONNECTION_CLOSE_FRAME
:
296 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT
,
297 base::Bind(&NetLogQuicConnectionCloseFrameCallback
,
298 frame
.connection_close_frame
));
302 case WINDOW_UPDATE_FRAME
:
304 NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT
,
305 base::Bind(&NetLogQuicWindowUpdateFrameCallback
,
306 frame
.window_update_frame
));
310 NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT
,
311 base::Bind(&NetLogQuicBlockedFrameCallback
,
312 frame
.blocked_frame
));
314 case STOP_WAITING_FRAME
:
316 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT
,
317 base::Bind(&NetLogQuicStopWaitingFrameCallback
,
318 frame
.stop_waiting_frame
));
321 DCHECK(false) << "Illegal frame type: " << frame
.type
;
325 void QuicConnectionLogger::OnPacketSent(
326 QuicPacketSequenceNumber sequence_number
,
327 EncryptionLevel level
,
328 const QuicEncryptedPacket
& packet
,
329 WriteResult result
) {
331 NetLog::TYPE_QUIC_SESSION_PACKET_SENT
,
332 base::Bind(&NetLogQuicPacketSentCallback
, sequence_number
, level
,
333 packet
.length(), result
));
336 void QuicConnectionLogger:: OnPacketRetransmitted(
337 QuicPacketSequenceNumber old_sequence_number
,
338 QuicPacketSequenceNumber new_sequence_number
) {
340 NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED
,
341 base::Bind(&NetLogQuicPacketRetransmittedCallback
,
342 old_sequence_number
, new_sequence_number
));
345 void QuicConnectionLogger::OnPacketReceived(const IPEndPoint
& self_address
,
346 const IPEndPoint
& peer_address
,
347 const QuicEncryptedPacket
& packet
) {
349 NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED
,
350 base::Bind(&NetLogQuicPacketCallback
, &self_address
, &peer_address
,
354 void QuicConnectionLogger::OnProtocolVersionMismatch(
355 QuicVersion received_version
) {
356 // TODO(rtenneti): Add logging.
359 void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader
& header
) {
361 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED
,
362 base::Bind(&NetLogQuicPacketHeaderCallback
, &header
));
363 if (largest_received_packet_sequence_number_
<
364 header
.packet_sequence_number
) {
365 QuicPacketSequenceNumber delta
= header
.packet_sequence_number
-
366 largest_received_packet_sequence_number_
;
368 // There is a gap between the largest packet previously received and
369 // the current packet. This indicates either loss, or out-of-order
371 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", delta
- 1);
373 largest_received_packet_sequence_number_
= header
.packet_sequence_number
;
375 if (header
.packet_sequence_number
< last_received_packet_sequence_number_
) {
376 ++out_of_order_recieved_packet_count_
;
377 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderGapReceived",
378 last_received_packet_sequence_number_
-
379 header
.packet_sequence_number
);
381 last_received_packet_sequence_number_
= header
.packet_sequence_number
;
384 void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame
& frame
) {
386 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED
,
387 base::Bind(&NetLogQuicStreamFrameCallback
, &frame
));
390 void QuicConnectionLogger::OnAckFrame(const QuicAckFrame
& frame
) {
392 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED
,
393 base::Bind(&NetLogQuicAckFrameCallback
, &frame
));
395 if (frame
.received_info
.is_truncated
)
396 ++num_truncated_acks_received_
;
398 if (frame
.received_info
.missing_packets
.empty())
401 SequenceNumberSet missing_packets
= frame
.received_info
.missing_packets
;
402 SequenceNumberSet::const_iterator it
= missing_packets
.lower_bound(
403 largest_received_missing_packet_sequence_number_
);
404 if (it
== missing_packets
.end())
407 if (*it
== largest_received_missing_packet_sequence_number_
) {
409 if (it
== missing_packets
.end())
412 // Scan through the list and log consecutive ranges of missing packets.
413 size_t num_consecutive_missing_packets
= 0;
414 QuicPacketSequenceNumber previous_missing_packet
= *it
- 1;
415 while (it
!= missing_packets
.end()) {
416 if (previous_missing_packet
== *it
- 1) {
417 ++num_consecutive_missing_packets
;
419 DCHECK_NE(0u, num_consecutive_missing_packets
);
420 UpdatePacketGapSentHistogram(num_consecutive_missing_packets
);
421 // Make sure this packet it included in the count.
422 num_consecutive_missing_packets
= 1;
424 previous_missing_packet
= *it
;
427 if (num_consecutive_missing_packets
!= 0) {
428 UpdatePacketGapSentHistogram(num_consecutive_missing_packets
);
430 largest_received_missing_packet_sequence_number_
=
431 *missing_packets
.rbegin();
434 void QuicConnectionLogger::OnCongestionFeedbackFrame(
435 const QuicCongestionFeedbackFrame
& frame
) {
437 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_RECEIVED
,
438 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback
, &frame
));
441 void QuicConnectionLogger::OnStopWaitingFrame(
442 const QuicStopWaitingFrame
& frame
) {
444 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED
,
445 base::Bind(&NetLogQuicStopWaitingFrameCallback
, &frame
));
448 void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame
& frame
) {
449 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer",
452 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_RECEIVED
,
453 base::Bind(&NetLogQuicRstStreamFrameCallback
, &frame
));
456 void QuicConnectionLogger::OnConnectionCloseFrame(
457 const QuicConnectionCloseFrame
& frame
) {
459 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED
,
460 base::Bind(&NetLogQuicConnectionCloseFrameCallback
, &frame
));
463 void QuicConnectionLogger::OnPublicResetPacket(
464 const QuicPublicResetPacket
& packet
) {
465 net_log_
.AddEvent(NetLog::TYPE_QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED
);
466 UpdatePublicResetAddressMismatchHistogram(client_address_
,
467 packet
.client_address
);
470 void QuicConnectionLogger::OnVersionNegotiationPacket(
471 const QuicVersionNegotiationPacket
& packet
) {
473 NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED
,
474 base::Bind(&NetLogQuicVersionNegotiationPacketCallback
, &packet
));
477 void QuicConnectionLogger::OnRevivedPacket(
478 const QuicPacketHeader
& revived_header
,
479 base::StringPiece payload
) {
481 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_REVIVED
,
482 base::Bind(&NetLogQuicPacketHeaderCallback
, &revived_header
));
485 void QuicConnectionLogger::OnCryptoHandshakeMessageReceived(
486 const CryptoHandshakeMessage
& message
) {
488 NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED
,
489 base::Bind(&NetLogQuicCryptoHandshakeMessageCallback
, &message
));
491 if (message
.tag() == kSHLO
) {
493 QuicSocketAddressCoder decoder
;
494 if (message
.GetStringPiece(kCADR
, &address
) &&
495 decoder
.Decode(address
.data(), address
.size())) {
496 client_address_
= IPEndPoint(decoder
.ip(), decoder
.port());
501 void QuicConnectionLogger::OnCryptoHandshakeMessageSent(
502 const CryptoHandshakeMessage
& message
) {
504 NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT
,
505 base::Bind(&NetLogQuicCryptoHandshakeMessageCallback
, &message
));
508 void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error
,
511 NetLog::TYPE_QUIC_SESSION_CLOSED
,
512 base::Bind(&NetLogQuicOnConnectionClosedCallback
, error
, from_peer
));
515 void QuicConnectionLogger::OnSuccessfulVersionNegotiation(
516 const QuicVersion
& version
) {
517 string quic_version
= QuicVersionToString(version
);
518 net_log_
.AddEvent(NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATED
,
519 NetLog::StringCallback("version", &quic_version
));