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. 4 5 #include "net/quic/quic_connection_logger.h" 6 7 #include <algorithm> 8 #include <string> 9 10 #include "base/bind.h" 11 #include "base/callback.h" 12 #include "base/metrics/histogram.h" 13 #include "base/metrics/sparse_histogram.h" 14 #include "base/strings/string_number_conversions.h" 15 #include "base/values.h" 16 #include "net/base/net_log.h" 17 #include "net/base/net_util.h" 18 #include "net/cert/cert_verify_result.h" 19 #include "net/cert/x509_certificate.h" 20 #include "net/quic/crypto/crypto_handshake_message.h" 21 #include "net/quic/crypto/crypto_protocol.h" 22 #include "net/quic/quic_address_mismatch.h" 23 #include "net/quic/quic_socket_address_coder.h" 24 25 using base::StringPiece; 26 using std::string; 27 28 namespace net { 29 30 namespace { 31 32 // We have ranges-of-buckets in the cumulative histogram (covering 21 packet 33 // sequences) of length 2, 3, 4, ... 22. 34 // Hence the largest sample is bounded by the sum of those numbers. 35 const int kBoundingSampleInCumulativeHistogram = ((2 + 22) * 21) / 2; 36 37 base::Value* NetLogQuicPacketCallback(const IPEndPoint* self_address, 38 const IPEndPoint* peer_address, 39 size_t packet_size, 40 NetLog::LogLevel /* log_level */) { 41 base::DictionaryValue* dict = new base::DictionaryValue(); 42 dict->SetString("self_address", self_address->ToString()); 43 dict->SetString("peer_address", peer_address->ToString()); 44 dict->SetInteger("size", packet_size); 45 return dict; 46 } 47 48 base::Value* NetLogQuicPacketSentCallback( 49 QuicPacketSequenceNumber sequence_number, 50 EncryptionLevel level, 51 TransmissionType transmission_type, 52 size_t packet_size, 53 WriteResult result, 54 NetLog::LogLevel /* log_level */) { 55 base::DictionaryValue* dict = new base::DictionaryValue(); 56 dict->SetInteger("encryption_level", level); 57 dict->SetInteger("transmission_type", transmission_type); 58 dict->SetString("packet_sequence_number", 59 base::Uint64ToString(sequence_number)); 60 dict->SetInteger("size", packet_size); 61 if (result.status != WRITE_STATUS_OK) { 62 dict->SetInteger("net_error", result.error_code); 63 } 64 return dict; 65 } 66 67 base::Value* NetLogQuicPacketRetransmittedCallback( 68 QuicPacketSequenceNumber old_sequence_number, 69 QuicPacketSequenceNumber new_sequence_number, 70 NetLog::LogLevel /* log_level */) { 71 base::DictionaryValue* dict = new base::DictionaryValue(); 72 dict->SetString("old_packet_sequence_number", 73 base::Uint64ToString(old_sequence_number)); 74 dict->SetString("new_packet_sequence_number", 75 base::Uint64ToString(new_sequence_number)); 76 return dict; 77 } 78 79 base::Value* NetLogQuicPacketHeaderCallback(const QuicPacketHeader* header, 80 NetLog::LogLevel /* log_level */) { 81 base::DictionaryValue* dict = new base::DictionaryValue(); 82 dict->SetString("connection_id", 83 base::Uint64ToString(header->public_header.connection_id)); 84 dict->SetInteger("reset_flag", header->public_header.reset_flag); 85 dict->SetInteger("version_flag", header->public_header.version_flag); 86 dict->SetString("packet_sequence_number", 87 base::Uint64ToString(header->packet_sequence_number)); 88 dict->SetInteger("entropy_flag", header->entropy_flag); 89 dict->SetInteger("fec_flag", header->fec_flag); 90 dict->SetInteger("fec_group", header->fec_group); 91 return dict; 92 } 93 94 base::Value* NetLogQuicStreamFrameCallback(const QuicStreamFrame* frame, 95 NetLog::LogLevel /* log_level */) { 96 base::DictionaryValue* dict = new base::DictionaryValue(); 97 dict->SetInteger("stream_id", frame->stream_id); 98 dict->SetBoolean("fin", frame->fin); 99 dict->SetString("offset", base::Uint64ToString(frame->offset)); 100 dict->SetInteger("length", frame->data.TotalBufferSize()); 101 return dict; 102 } 103 104 base::Value* NetLogQuicAckFrameCallback(const QuicAckFrame* frame, 105 NetLog::LogLevel /* log_level */) { 106 base::DictionaryValue* dict = new base::DictionaryValue(); 107 dict->SetString("largest_observed", 108 base::Uint64ToString(frame->largest_observed)); 109 dict->SetInteger("delta_time_largest_observed_us", 110 frame->delta_time_largest_observed.ToMicroseconds()); 111 dict->SetInteger("entropy_hash", 112 frame->entropy_hash); 113 dict->SetBoolean("truncated", frame->is_truncated); 114 115 base::ListValue* missing = new base::ListValue(); 116 dict->Set("missing_packets", missing); 117 const SequenceNumberSet& missing_packets = frame->missing_packets; 118 for (SequenceNumberSet::const_iterator it = missing_packets.begin(); 119 it != missing_packets.end(); ++it) { 120 missing->AppendString(base::Uint64ToString(*it)); 121 } 122 123 base::ListValue* revived = new base::ListValue(); 124 dict->Set("revived_packets", revived); 125 const SequenceNumberSet& revived_packets = frame->revived_packets; 126 for (SequenceNumberSet::const_iterator it = revived_packets.begin(); 127 it != revived_packets.end(); ++it) { 128 revived->AppendString(base::Uint64ToString(*it)); 129 } 130 131 base::ListValue* received = new base::ListValue(); 132 dict->Set("received_packet_times", received); 133 const PacketTimeList& received_times = frame->received_packet_times; 134 for (PacketTimeList::const_iterator it = received_times.begin(); 135 it != received_times.end(); ++it) { 136 base::DictionaryValue* info = new base::DictionaryValue(); 137 info->SetInteger("sequence_number", it->first); 138 info->SetInteger("received", it->second.ToDebuggingValue()); 139 received->Append(info); 140 } 141 142 return dict; 143 } 144 145 base::Value* NetLogQuicCongestionFeedbackFrameCallback( 146 const QuicCongestionFeedbackFrame* frame, 147 NetLog::LogLevel /* log_level */) { 148 base::DictionaryValue* dict = new base::DictionaryValue(); 149 switch (frame->type) { 150 case kTCP: 151 dict->SetString("type", "TCP"); 152 dict->SetInteger("receive_window", frame->tcp.receive_window); 153 break; 154 } 155 156 return dict; 157 } 158 159 base::Value* NetLogQuicRstStreamFrameCallback( 160 const QuicRstStreamFrame* frame, 161 NetLog::LogLevel /* log_level */) { 162 base::DictionaryValue* dict = new base::DictionaryValue(); 163 dict->SetInteger("stream_id", frame->stream_id); 164 dict->SetInteger("quic_rst_stream_error", frame->error_code); 165 dict->SetString("details", frame->error_details); 166 return dict; 167 } 168 169 base::Value* NetLogQuicConnectionCloseFrameCallback( 170 const QuicConnectionCloseFrame* frame, 171 NetLog::LogLevel /* log_level */) { 172 base::DictionaryValue* dict = new base::DictionaryValue(); 173 dict->SetInteger("quic_error", frame->error_code); 174 dict->SetString("details", frame->error_details); 175 return dict; 176 } 177 178 base::Value* NetLogQuicWindowUpdateFrameCallback( 179 const QuicWindowUpdateFrame* frame, 180 NetLog::LogLevel /* log_level */) { 181 base::DictionaryValue* dict = new base::DictionaryValue(); 182 dict->SetInteger("stream_id", frame->stream_id); 183 dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset)); 184 return dict; 185 } 186 187 base::Value* NetLogQuicBlockedFrameCallback( 188 const QuicBlockedFrame* frame, 189 NetLog::LogLevel /* log_level */) { 190 base::DictionaryValue* dict = new base::DictionaryValue(); 191 dict->SetInteger("stream_id", frame->stream_id); 192 return dict; 193 } 194 195 base::Value* NetLogQuicGoAwayFrameCallback( 196 const QuicGoAwayFrame* frame, 197 NetLog::LogLevel /* log_level */) { 198 base::DictionaryValue* dict = new base::DictionaryValue(); 199 dict->SetInteger("quic_error", frame->error_code); 200 dict->SetInteger("last_good_stream_id", frame->last_good_stream_id); 201 dict->SetString("reason_phrase", frame->reason_phrase); 202 return dict; 203 } 204 205 base::Value* NetLogQuicStopWaitingFrameCallback( 206 const QuicStopWaitingFrame* frame, 207 NetLog::LogLevel /* log_level */) { 208 base::DictionaryValue* dict = new base::DictionaryValue(); 209 base::DictionaryValue* sent_info = new base::DictionaryValue(); 210 dict->Set("sent_info", sent_info); 211 sent_info->SetString("least_unacked", 212 base::Uint64ToString(frame->least_unacked)); 213 return dict; 214 } 215 216 base::Value* NetLogQuicVersionNegotiationPacketCallback( 217 const QuicVersionNegotiationPacket* packet, 218 NetLog::LogLevel /* log_level */) { 219 base::DictionaryValue* dict = new base::DictionaryValue(); 220 base::ListValue* versions = new base::ListValue(); 221 dict->Set("versions", versions); 222 for (QuicVersionVector::const_iterator it = packet->versions.begin(); 223 it != packet->versions.end(); ++it) { 224 versions->AppendString(QuicVersionToString(*it)); 225 } 226 return dict; 227 } 228 229 base::Value* NetLogQuicCryptoHandshakeMessageCallback( 230 const CryptoHandshakeMessage* message, 231 NetLog::LogLevel /* log_level */) { 232 base::DictionaryValue* dict = new base::DictionaryValue(); 233 dict->SetString("quic_crypto_handshake_message", message->DebugString()); 234 return dict; 235 } 236 237 base::Value* NetLogQuicOnConnectionClosedCallback( 238 QuicErrorCode error, 239 bool from_peer, 240 NetLog::LogLevel /* log_level */) { 241 base::DictionaryValue* dict = new base::DictionaryValue(); 242 dict->SetInteger("quic_error", error); 243 dict->SetBoolean("from_peer", from_peer); 244 return dict; 245 } 246 247 base::Value* NetLogQuicCertificateVerifiedCallback( 248 scoped_refptr<X509Certificate> cert, 249 NetLog::LogLevel /* log_level */) { 250 // Only the subjects are logged so that we can investigate connection pooling. 251 // More fields could be logged in the future. 252 std::vector<std::string> dns_names; 253 cert->GetDNSNames(&dns_names); 254 base::DictionaryValue* dict = new base::DictionaryValue(); 255 base::ListValue* subjects = new base::ListValue(); 256 for (std::vector<std::string>::const_iterator it = dns_names.begin(); 257 it != dns_names.end(); it++) { 258 subjects->Append(new base::StringValue(*it)); 259 } 260 dict->Set("subjects", subjects); 261 return dict; 262 } 263 264 void UpdatePacketGapSentHistogram(size_t num_consecutive_missing_packets) { 265 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapSent", 266 num_consecutive_missing_packets); 267 } 268 269 void UpdatePublicResetAddressMismatchHistogram( 270 const IPEndPoint& server_hello_address, 271 const IPEndPoint& public_reset_address) { 272 int sample = GetAddressMismatch(server_hello_address, public_reset_address); 273 // We are seemingly talking to an older server that does not support the 274 // feature, so we can't report the results in the histogram. 275 if (sample < 0) { 276 return; 277 } 278 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch2", 279 sample, QUIC_ADDRESS_MISMATCH_MAX); 280 } 281 282 const char* GetConnectionDescriptionString() { 283 NetworkChangeNotifier::ConnectionType type = 284 NetworkChangeNotifier::GetConnectionType(); 285 const char* description = NetworkChangeNotifier::ConnectionTypeToString(type); 286 // Most platforms don't distingish Wifi vs Etherenet, and call everything 287 // CONNECTION_UNKNOWN :-(. We'll tease out some details when we are on WiFi, 288 // and hopefully leave only ethernet (with no WiFi available) in the 289 // CONNECTION_UNKNOWN category. This *might* err if there is both ethernet, 290 // as well as WiFi, where WiFi was not being used that much. 291 // This function only seems usefully defined on Windows currently. 292 if (type == NetworkChangeNotifier::CONNECTION_UNKNOWN || 293 type == NetworkChangeNotifier::CONNECTION_WIFI) { 294 WifiPHYLayerProtocol wifi_type = GetWifiPHYLayerProtocol(); 295 switch (wifi_type) { 296 case WIFI_PHY_LAYER_PROTOCOL_NONE: 297 // No wifi support or no associated AP. 298 break; 299 case WIFI_PHY_LAYER_PROTOCOL_ANCIENT: 300 // An obsolete modes introduced by the original 802.11, e.g. IR, FHSS. 301 description = "CONNECTION_WIFI_ANCIENT"; 302 break; 303 case WIFI_PHY_LAYER_PROTOCOL_A: 304 // 802.11a, OFDM-based rates. 305 description = "CONNECTION_WIFI_802.11a"; 306 break; 307 case WIFI_PHY_LAYER_PROTOCOL_B: 308 // 802.11b, DSSS or HR DSSS. 309 description = "CONNECTION_WIFI_802.11b"; 310 break; 311 case WIFI_PHY_LAYER_PROTOCOL_G: 312 // 802.11g, same rates as 802.11a but compatible with 802.11b. 313 description = "CONNECTION_WIFI_802.11g"; 314 break; 315 case WIFI_PHY_LAYER_PROTOCOL_N: 316 // 802.11n, HT rates. 317 description = "CONNECTION_WIFI_802.11n"; 318 break; 319 case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN: 320 // Unclassified mode or failure to identify. 321 break; 322 } 323 } 324 return description; 325 } 326 327 // If |address| is an IPv4-mapped IPv6 address, returns ADDRESS_FAMILY_IPV4 328 // instead of ADDRESS_FAMILY_IPV6. Othewise, behaves like GetAddressFamily(). 329 AddressFamily GetRealAddressFamily(const IPAddressNumber& address) { 330 return IsIPv4Mapped(address) ? ADDRESS_FAMILY_IPV4 : 331 GetAddressFamily(address); 332 } 333 334 } // namespace 335 336 QuicConnectionLogger::QuicConnectionLogger(const BoundNetLog& net_log) 337 : net_log_(net_log), 338 last_received_packet_sequence_number_(0), 339 last_received_packet_size_(0), 340 largest_received_packet_sequence_number_(0), 341 largest_received_missing_packet_sequence_number_(0), 342 num_out_of_order_received_packets_(0), 343 num_packets_received_(0), 344 num_truncated_acks_sent_(0), 345 num_truncated_acks_received_(0), 346 num_frames_received_(0), 347 num_duplicate_frames_received_(0), 348 num_incorrect_connection_ids_(0), 349 num_undecryptable_packets_(0), 350 num_duplicate_packets_(0), 351 connection_description_(GetConnectionDescriptionString()) { 352 } 353 354 QuicConnectionLogger::~QuicConnectionLogger() { 355 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderPacketsReceived", 356 num_out_of_order_received_packets_); 357 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent", 358 num_truncated_acks_sent_); 359 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived", 360 num_truncated_acks_received_); 361 UMA_HISTOGRAM_COUNTS("Net.QuicSession.IncorrectConnectionIDsReceived", 362 num_incorrect_connection_ids_); 363 UMA_HISTOGRAM_COUNTS("Net.QuicSession.UndecryptablePacketsReceived", 364 num_undecryptable_packets_); 365 UMA_HISTOGRAM_COUNTS("Net.QuicSession.DuplicatePacketsReceived", 366 num_duplicate_packets_); 367 368 if (num_frames_received_ > 0) { 369 int duplicate_stream_frame_per_thousand = 370 num_duplicate_frames_received_ * 1000 / num_frames_received_; 371 if (num_packets_received_ < 100) { 372 UMA_HISTOGRAM_CUSTOM_COUNTS( 373 "Net.QuicSession.StreamFrameDuplicatedShortConnection", 374 duplicate_stream_frame_per_thousand, 1, 1000, 75); 375 } else { 376 UMA_HISTOGRAM_CUSTOM_COUNTS( 377 "Net.QuicSession.StreamFrameDuplicatedLongConnection", 378 duplicate_stream_frame_per_thousand, 1, 1000, 75); 379 380 } 381 } 382 383 RecordLossHistograms(); 384 } 385 386 void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { 387 switch (frame.type) { 388 case PADDING_FRAME: 389 break; 390 case STREAM_FRAME: 391 net_log_.AddEvent( 392 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_SENT, 393 base::Bind(&NetLogQuicStreamFrameCallback, frame.stream_frame)); 394 break; 395 case ACK_FRAME: { 396 net_log_.AddEvent( 397 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_SENT, 398 base::Bind(&NetLogQuicAckFrameCallback, frame.ack_frame)); 399 const SequenceNumberSet& missing_packets = 400 frame.ack_frame->missing_packets; 401 const uint8 max_ranges = std::numeric_limits<uint8>::max(); 402 // Compute an upper bound on the number of NACK ranges. If the bound 403 // is below the max, then it clearly isn't truncated. 404 if (missing_packets.size() < max_ranges || 405 (*missing_packets.rbegin() - *missing_packets.begin() - 406 missing_packets.size() + 1) < max_ranges) { 407 break; 408 } 409 size_t num_ranges = 0; 410 QuicPacketSequenceNumber last_missing = 0; 411 for (SequenceNumberSet::const_iterator it = missing_packets.begin(); 412 it != missing_packets.end(); ++it) { 413 if (*it != last_missing + 1 && ++num_ranges >= max_ranges) { 414 ++num_truncated_acks_sent_; 415 break; 416 } 417 last_missing = *it; 418 } 419 break; 420 } 421 case CONGESTION_FEEDBACK_FRAME: 422 net_log_.AddEvent( 423 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_SENT, 424 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, 425 frame.congestion_feedback_frame)); 426 break; 427 case RST_STREAM_FRAME: 428 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient", 429 frame.rst_stream_frame->error_code); 430 net_log_.AddEvent( 431 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_SENT, 432 base::Bind(&NetLogQuicRstStreamFrameCallback, 433 frame.rst_stream_frame)); 434 break; 435 case CONNECTION_CLOSE_FRAME: 436 net_log_.AddEvent( 437 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT, 438 base::Bind(&NetLogQuicConnectionCloseFrameCallback, 439 frame.connection_close_frame)); 440 break; 441 case GOAWAY_FRAME: 442 net_log_.AddEvent( 443 NetLog::TYPE_QUIC_SESSION_GOAWAY_FRAME_SENT, 444 base::Bind(&NetLogQuicGoAwayFrameCallback, 445 frame.goaway_frame)); 446 break; 447 case WINDOW_UPDATE_FRAME: 448 net_log_.AddEvent( 449 NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT, 450 base::Bind(&NetLogQuicWindowUpdateFrameCallback, 451 frame.window_update_frame)); 452 break; 453 case BLOCKED_FRAME: 454 net_log_.AddEvent( 455 NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT, 456 base::Bind(&NetLogQuicBlockedFrameCallback, 457 frame.blocked_frame)); 458 break; 459 case STOP_WAITING_FRAME: 460 net_log_.AddEvent( 461 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT, 462 base::Bind(&NetLogQuicStopWaitingFrameCallback, 463 frame.stop_waiting_frame)); 464 break; 465 case PING_FRAME: 466 // PingFrame has no contents to log, so just record that it was sent. 467 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_SENT); 468 break; 469 default: 470 DCHECK(false) << "Illegal frame type: " << frame.type; 471 } 472 } 473 474 void QuicConnectionLogger::OnPacketSent( 475 QuicPacketSequenceNumber sequence_number, 476 EncryptionLevel level, 477 TransmissionType transmission_type, 478 const QuicEncryptedPacket& packet, 479 WriteResult result) { 480 net_log_.AddEvent( 481 NetLog::TYPE_QUIC_SESSION_PACKET_SENT, 482 base::Bind(&NetLogQuicPacketSentCallback, sequence_number, level, 483 transmission_type, packet.length(), result)); 484 } 485 486 void QuicConnectionLogger:: OnPacketRetransmitted( 487 QuicPacketSequenceNumber old_sequence_number, 488 QuicPacketSequenceNumber new_sequence_number) { 489 net_log_.AddEvent( 490 NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED, 491 base::Bind(&NetLogQuicPacketRetransmittedCallback, 492 old_sequence_number, new_sequence_number)); 493 } 494 495 void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address, 496 const IPEndPoint& peer_address, 497 const QuicEncryptedPacket& packet) { 498 if (local_address_from_self_.GetFamily() == ADDRESS_FAMILY_UNSPECIFIED) { 499 local_address_from_self_ = self_address; 500 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromSelf", 501 GetRealAddressFamily(self_address.address()), 502 ADDRESS_FAMILY_LAST); 503 } 504 505 last_received_packet_size_ = packet.length(); 506 net_log_.AddEvent( 507 NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED, 508 base::Bind(&NetLogQuicPacketCallback, &self_address, &peer_address, 509 packet.length())); 510 } 511 512 void QuicConnectionLogger::OnIncorrectConnectionId( 513 QuicConnectionId connection_id) { 514 ++num_incorrect_connection_ids_; 515 } 516 517 void QuicConnectionLogger::OnUndecryptablePacket() { 518 ++num_undecryptable_packets_; 519 } 520 521 void QuicConnectionLogger::OnDuplicatePacket( 522 QuicPacketSequenceNumber sequence_number) { 523 ++num_duplicate_packets_; 524 } 525 526 void QuicConnectionLogger::OnProtocolVersionMismatch( 527 QuicVersion received_version) { 528 // TODO(rtenneti): Add logging. 529 } 530 531 void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) { 532 net_log_.AddEvent( 533 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED, 534 base::Bind(&NetLogQuicPacketHeaderCallback, &header)); 535 ++num_packets_received_; 536 if (largest_received_packet_sequence_number_ < 537 header.packet_sequence_number) { 538 QuicPacketSequenceNumber delta = header.packet_sequence_number - 539 largest_received_packet_sequence_number_; 540 if (delta > 1) { 541 // There is a gap between the largest packet previously received and 542 // the current packet. This indicates either loss, or out-of-order 543 // delivery. 544 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", delta - 1); 545 } 546 largest_received_packet_sequence_number_ = header.packet_sequence_number; 547 } 548 if (header.packet_sequence_number < received_packets_.size()) 549 received_packets_[header.packet_sequence_number] = true; 550 if (header.packet_sequence_number < last_received_packet_sequence_number_) { 551 ++num_out_of_order_received_packets_; 552 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderGapReceived", 553 last_received_packet_sequence_number_ - 554 header.packet_sequence_number); 555 } 556 last_received_packet_sequence_number_ = header.packet_sequence_number; 557 } 558 559 void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame& frame) { 560 net_log_.AddEvent( 561 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED, 562 base::Bind(&NetLogQuicStreamFrameCallback, &frame)); 563 } 564 565 void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) { 566 net_log_.AddEvent( 567 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED, 568 base::Bind(&NetLogQuicAckFrameCallback, &frame)); 569 570 const size_t kApproximateLargestSoloAckBytes = 100; 571 if (last_received_packet_sequence_number_ < received_acks_.size() && 572 last_received_packet_size_ < kApproximateLargestSoloAckBytes) 573 received_acks_[last_received_packet_sequence_number_] = true; 574 575 if (frame.is_truncated) 576 ++num_truncated_acks_received_; 577 578 if (frame.missing_packets.empty()) 579 return; 580 581 SequenceNumberSet missing_packets = frame.missing_packets; 582 SequenceNumberSet::const_iterator it = missing_packets.lower_bound( 583 largest_received_missing_packet_sequence_number_); 584 if (it == missing_packets.end()) 585 return; 586 587 if (*it == largest_received_missing_packet_sequence_number_) { 588 ++it; 589 if (it == missing_packets.end()) 590 return; 591 } 592 // Scan through the list and log consecutive ranges of missing packets. 593 size_t num_consecutive_missing_packets = 0; 594 QuicPacketSequenceNumber previous_missing_packet = *it - 1; 595 while (it != missing_packets.end()) { 596 if (previous_missing_packet == *it - 1) { 597 ++num_consecutive_missing_packets; 598 } else { 599 DCHECK_NE(0u, num_consecutive_missing_packets); 600 UpdatePacketGapSentHistogram(num_consecutive_missing_packets); 601 // Make sure this packet it included in the count. 602 num_consecutive_missing_packets = 1; 603 } 604 previous_missing_packet = *it; 605 ++it; 606 } 607 if (num_consecutive_missing_packets != 0) { 608 UpdatePacketGapSentHistogram(num_consecutive_missing_packets); 609 } 610 largest_received_missing_packet_sequence_number_ = 611 *missing_packets.rbegin(); 612 } 613 614 void QuicConnectionLogger::OnCongestionFeedbackFrame( 615 const QuicCongestionFeedbackFrame& frame) { 616 net_log_.AddEvent( 617 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_RECEIVED, 618 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, &frame)); 619 } 620 621 void QuicConnectionLogger::OnStopWaitingFrame( 622 const QuicStopWaitingFrame& frame) { 623 net_log_.AddEvent( 624 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED, 625 base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame)); 626 } 627 628 void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) { 629 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer", 630 frame.error_code); 631 net_log_.AddEvent( 632 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_RECEIVED, 633 base::Bind(&NetLogQuicRstStreamFrameCallback, &frame)); 634 } 635 636 void QuicConnectionLogger::OnConnectionCloseFrame( 637 const QuicConnectionCloseFrame& frame) { 638 net_log_.AddEvent( 639 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED, 640 base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame)); 641 } 642 643 void QuicConnectionLogger::OnWindowUpdateFrame( 644 const QuicWindowUpdateFrame& frame) { 645 net_log_.AddEvent( 646 NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_RECEIVED, 647 base::Bind(&NetLogQuicWindowUpdateFrameCallback, &frame)); 648 } 649 650 void QuicConnectionLogger::OnBlockedFrame(const QuicBlockedFrame& frame) { 651 net_log_.AddEvent( 652 NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_RECEIVED, 653 base::Bind(&NetLogQuicBlockedFrameCallback, &frame)); 654 } 655 656 void QuicConnectionLogger::OnGoAwayFrame(const QuicGoAwayFrame& frame) { 657 net_log_.AddEvent( 658 NetLog::TYPE_QUIC_SESSION_GOAWAY_FRAME_RECEIVED, 659 base::Bind(&NetLogQuicGoAwayFrameCallback, &frame)); 660 } 661 662 void QuicConnectionLogger::OnPingFrame(const QuicPingFrame& frame) { 663 // PingFrame has no contents to log, so just record that it was received. 664 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PING_FRAME_RECEIVED); 665 } 666 667 void QuicConnectionLogger::OnPublicResetPacket( 668 const QuicPublicResetPacket& packet) { 669 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PUBLIC_RESET_PACKET_RECEIVED); 670 UpdatePublicResetAddressMismatchHistogram(local_address_from_shlo_, 671 packet.client_address); 672 } 673 674 void QuicConnectionLogger::OnVersionNegotiationPacket( 675 const QuicVersionNegotiationPacket& packet) { 676 net_log_.AddEvent( 677 NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATION_PACKET_RECEIVED, 678 base::Bind(&NetLogQuicVersionNegotiationPacketCallback, &packet)); 679 } 680 681 void QuicConnectionLogger::OnRevivedPacket( 682 const QuicPacketHeader& revived_header, 683 base::StringPiece payload) { 684 net_log_.AddEvent( 685 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_REVIVED, 686 base::Bind(&NetLogQuicPacketHeaderCallback, &revived_header)); 687 } 688 689 void QuicConnectionLogger::OnCryptoHandshakeMessageReceived( 690 const CryptoHandshakeMessage& message) { 691 net_log_.AddEvent( 692 NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_RECEIVED, 693 base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message)); 694 695 if (message.tag() == kSHLO) { 696 StringPiece address; 697 QuicSocketAddressCoder decoder; 698 if (message.GetStringPiece(kCADR, &address) && 699 decoder.Decode(address.data(), address.size())) { 700 local_address_from_shlo_ = IPEndPoint(decoder.ip(), decoder.port()); 701 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.ConnectionTypeFromPeer", 702 GetRealAddressFamily( 703 local_address_from_shlo_.address()), 704 ADDRESS_FAMILY_LAST); 705 } 706 } 707 } 708 709 void QuicConnectionLogger::OnCryptoHandshakeMessageSent( 710 const CryptoHandshakeMessage& message) { 711 net_log_.AddEvent( 712 NetLog::TYPE_QUIC_SESSION_CRYPTO_HANDSHAKE_MESSAGE_SENT, 713 base::Bind(&NetLogQuicCryptoHandshakeMessageCallback, &message)); 714 } 715 716 void QuicConnectionLogger::OnConnectionClosed(QuicErrorCode error, 717 bool from_peer) { 718 net_log_.AddEvent( 719 NetLog::TYPE_QUIC_SESSION_CLOSED, 720 base::Bind(&NetLogQuicOnConnectionClosedCallback, error, from_peer)); 721 } 722 723 void QuicConnectionLogger::OnSuccessfulVersionNegotiation( 724 const QuicVersion& version) { 725 string quic_version = QuicVersionToString(version); 726 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_VERSION_NEGOTIATED, 727 NetLog::StringCallback("version", &quic_version)); 728 } 729 730 void QuicConnectionLogger::UpdateReceivedFrameCounts( 731 QuicStreamId stream_id, 732 int num_frames_received, 733 int num_duplicate_frames_received) { 734 if (stream_id != kCryptoStreamId) { 735 num_frames_received_ += num_frames_received; 736 num_duplicate_frames_received_ += num_duplicate_frames_received; 737 } 738 } 739 740 void QuicConnectionLogger::OnCertificateVerified( 741 const CertVerifyResult& result) { 742 net_log_.AddEvent( 743 NetLog::TYPE_QUIC_SESSION_CERTIFICATE_VERIFIED, 744 base::Bind(&NetLogQuicCertificateVerifiedCallback, result.verified_cert)); 745 } 746 747 base::HistogramBase* QuicConnectionLogger::GetPacketSequenceNumberHistogram( 748 const char* statistic_name) const { 749 string prefix("Net.QuicSession.PacketReceived_"); 750 return base::LinearHistogram::FactoryGet( 751 prefix + statistic_name + connection_description_, 752 1, received_packets_.size(), received_packets_.size() + 1, 753 base::HistogramBase::kUmaTargetedHistogramFlag); 754 } 755 756 base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram( 757 const char* which_6) const { 758 // This histogram takes a binary encoding of the 6 consecutive packets 759 // received. As a result, there are 64 possible sample-patterns. 760 string prefix("Net.QuicSession.6PacketsPatternsReceived_"); 761 return base::LinearHistogram::FactoryGet( 762 prefix + which_6 + connection_description_, 1, 64, 65, 763 base::HistogramBase::kUmaTargetedHistogramFlag); 764 } 765 766 base::HistogramBase* QuicConnectionLogger::Get21CumulativeHistogram( 767 const char* which_21) const { 768 // This histogram contains, for each sequence of 21 packets, the results from 769 // 21 distinct questions about that sequence. Conceptually the histogtram is 770 // broken into 21 distinct ranges, and one sample is added into each of those 771 // ranges whenever we process a set of 21 packets. 772 // There is a little rendundancy, as each "range" must have the same number 773 // of samples, all told, but the histogram is a tad easier to read this way. 774 // The questions are: 775 // Was the first packet present (bucket 0==>no; bucket 1==>yes) 776 // Of the first two packets, how many were present? (bucket 2==> none; 777 // bucket 3==> 1 of 2; bucket 4==> 2 of 2) 778 // Of the first three packets, how many were present? (bucket 5==>none; 779 // bucket 6==> 1 of 3; bucket 7==> 2 of 3; bucket 8==> 3 of 3). 780 // etc. 781 string prefix("Net.QuicSession.21CumulativePacketsReceived_"); 782 return base::LinearHistogram::FactoryGet( 783 prefix + which_21 + connection_description_, 784 1, kBoundingSampleInCumulativeHistogram, 785 kBoundingSampleInCumulativeHistogram + 1, 786 base::HistogramBase::kUmaTargetedHistogramFlag); 787 } 788 789 // static 790 void QuicConnectionLogger::AddTo21CumulativeHistogram( 791 base::HistogramBase* histogram, 792 int bit_mask_of_packets, 793 int valid_bits_in_mask) { 794 DCHECK_LE(valid_bits_in_mask, 21); 795 DCHECK_LT(bit_mask_of_packets, 1 << 21); 796 const int blank_bits_in_mask = 21 - valid_bits_in_mask; 797 DCHECK_EQ(bit_mask_of_packets & ((1 << blank_bits_in_mask) - 1), 0); 798 bit_mask_of_packets >>= blank_bits_in_mask; 799 int bits_so_far = 0; 800 int range_start = 0; 801 for (int i = 1; i <= valid_bits_in_mask; ++i) { 802 bits_so_far += bit_mask_of_packets & 1; 803 bit_mask_of_packets >>= 1; 804 DCHECK_LT(range_start + bits_so_far, kBoundingSampleInCumulativeHistogram); 805 histogram->Add(range_start + bits_so_far); 806 range_start += i + 1; 807 } 808 } 809 810 void QuicConnectionLogger::RecordAggregatePacketLossRate() const { 811 // For short connections under 22 packets in length, we'll rely on the 812 // Net.QuicSession.21CumulativePacketsReceived_* histogram to indicate packet 813 // loss rates. This way we avoid tremendously anomalous contributions to our 814 // histogram. (e.g., if we only got 5 packets, but lost 1, we'd otherwise 815 // record a 20% loss in this histogram!). We may still get some strange data 816 // (1 loss in 22 is still high :-/). 817 if (largest_received_packet_sequence_number_ <= 21) 818 return; 819 820 QuicPacketSequenceNumber divisor = largest_received_packet_sequence_number_; 821 QuicPacketSequenceNumber numerator = divisor - num_packets_received_; 822 if (divisor < 100000) 823 numerator *= 1000; 824 else 825 divisor /= 1000; 826 string prefix("Net.QuicSession.PacketLossRate_"); 827 base::HistogramBase* histogram = base::Histogram::FactoryGet( 828 prefix + connection_description_, 1, 1000, 75, 829 base::HistogramBase::kUmaTargetedHistogramFlag); 830 histogram->Add(numerator / divisor); 831 } 832 833 void QuicConnectionLogger::RecordLossHistograms() const { 834 if (largest_received_packet_sequence_number_ == 0) 835 return; // Connection was never used. 836 RecordAggregatePacketLossRate(); 837 838 base::HistogramBase* is_not_ack_histogram = 839 GetPacketSequenceNumberHistogram("IsNotAck_"); 840 base::HistogramBase* is_an_ack_histogram = 841 GetPacketSequenceNumberHistogram("IsAnAck_"); 842 base::HistogramBase* packet_arrived_histogram = 843 GetPacketSequenceNumberHistogram("Ack_"); 844 base::HistogramBase* packet_missing_histogram = 845 GetPacketSequenceNumberHistogram("Nack_"); 846 base::HistogramBase* ongoing_cumulative_packet_histogram = 847 Get21CumulativeHistogram("Some21s_"); 848 base::HistogramBase* first_cumulative_packet_histogram = 849 Get21CumulativeHistogram("First21_"); 850 base::HistogramBase* six_packet_histogram = Get6PacketHistogram("Some6s_"); 851 852 DCHECK_EQ(received_packets_.size(), received_acks_.size()); 853 const QuicPacketSequenceNumber last_index = 854 std::min<QuicPacketSequenceNumber>(received_packets_.size() - 1, 855 largest_received_packet_sequence_number_); 856 const QuicPacketSequenceNumber index_of_first_21_contribution = 857 std::min<QuicPacketSequenceNumber>(21, last_index); 858 // Bit pattern of consecutively received packets that is maintained as we scan 859 // through the received_packets_ vector. Less significant bits correspond to 860 // less recent packets, and only the low order 21 bits are ever defined. 861 // Bit is 1 iff corresponding packet was received. 862 int packet_pattern_21 = 0; 863 // Zero is an invalid packet sequence number. 864 DCHECK(!received_packets_[0]); 865 for (size_t i = 1; i <= last_index; ++i) { 866 if (received_acks_[i]) 867 is_an_ack_histogram->Add(i); 868 else 869 is_not_ack_histogram->Add(i); 870 871 packet_pattern_21 >>= 1; 872 if (received_packets_[i]) { 873 packet_arrived_histogram->Add(i); 874 packet_pattern_21 |= (1 << 20); // Turn on the 21st bit. 875 } else { 876 packet_missing_histogram->Add(i); 877 } 878 879 if (i == index_of_first_21_contribution) { 880 AddTo21CumulativeHistogram(first_cumulative_packet_histogram, 881 packet_pattern_21, i); 882 } 883 // We'll just record for non-overlapping ranges, to reduce histogramming 884 // cost for now. Each call does 21 separate histogram additions. 885 if (i > 21 || i % 21 == 0) { 886 AddTo21CumulativeHistogram(ongoing_cumulative_packet_histogram, 887 packet_pattern_21, 21); 888 } 889 890 if (i < 6) 891 continue; // Not enough packets to do any pattern recording. 892 int recent_6_mask = packet_pattern_21 >> 15; 893 DCHECK_LT(recent_6_mask, 64); 894 if (i == 6) { 895 Get6PacketHistogram("First6_")->Add(recent_6_mask); 896 continue; 897 } 898 // Record some overlapping patterns, to get a better picture, since this is 899 // not very expensive. 900 if (i % 3 == 0) 901 six_packet_histogram->Add(recent_6_mask); 902 } 903 } 904 905 } // namespace net 906