| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/quic_connection_logger.h" | 5 #include "net/quic/quic_connection_logger.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 dict->Set("received_info", received_info); | 110 dict->Set("received_info", received_info); |
| 111 received_info->SetString( | 111 received_info->SetString( |
| 112 "largest_observed", | 112 "largest_observed", |
| 113 base::Uint64ToString(frame->received_info.largest_observed)); | 113 base::Uint64ToString(frame->received_info.largest_observed)); |
| 114 received_info->SetBoolean("truncated", frame->received_info.is_truncated); | 114 received_info->SetBoolean("truncated", frame->received_info.is_truncated); |
| 115 base::ListValue* missing = new base::ListValue(); | 115 base::ListValue* missing = new base::ListValue(); |
| 116 received_info->Set("missing_packets", missing); | 116 received_info->Set("missing_packets", missing); |
| 117 const SequenceNumberSet& missing_packets = | 117 const SequenceNumberSet& missing_packets = |
| 118 frame->received_info.missing_packets; | 118 frame->received_info.missing_packets; |
| 119 for (SequenceNumberSet::const_iterator it = missing_packets.begin(); | 119 for (SequenceNumberSet::const_iterator it = missing_packets.begin(); |
| 120 it != missing_packets.end(); ++it) { | 120 it != missing_packets.end(); |
| 121 ++it) { |
| 121 missing->AppendString(base::Uint64ToString(*it)); | 122 missing->AppendString(base::Uint64ToString(*it)); |
| 122 } | 123 } |
| 123 return dict; | 124 return dict; |
| 124 } | 125 } |
| 125 | 126 |
| 126 base::Value* NetLogQuicCongestionFeedbackFrameCallback( | 127 base::Value* NetLogQuicCongestionFeedbackFrameCallback( |
| 127 const QuicCongestionFeedbackFrame* frame, | 128 const QuicCongestionFeedbackFrame* frame, |
| 128 NetLog::LogLevel /* log_level */) { | 129 NetLog::LogLevel /* log_level */) { |
| 129 base::DictionaryValue* dict = new base::DictionaryValue(); | 130 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 130 switch (frame->type) { | 131 switch (frame->type) { |
| 131 case kInterArrival: { | 132 case kInterArrival: { |
| 132 dict->SetString("type", "InterArrival"); | 133 dict->SetString("type", "InterArrival"); |
| 133 base::ListValue* received = new base::ListValue(); | 134 base::ListValue* received = new base::ListValue(); |
| 134 dict->Set("received_packets", received); | 135 dict->Set("received_packets", received); |
| 135 for (TimeMap::const_iterator it = | 136 for (TimeMap::const_iterator it = |
| 136 frame->inter_arrival.received_packet_times.begin(); | 137 frame->inter_arrival.received_packet_times.begin(); |
| 137 it != frame->inter_arrival.received_packet_times.end(); ++it) { | 138 it != frame->inter_arrival.received_packet_times.end(); |
| 139 ++it) { |
| 138 string value = base::Uint64ToString(it->first) + "@" + | 140 string value = base::Uint64ToString(it->first) + "@" + |
| 139 base::Uint64ToString(it->second.ToDebuggingValue()); | 141 base::Uint64ToString(it->second.ToDebuggingValue()); |
| 140 received->AppendString(value); | 142 received->AppendString(value); |
| 141 } | 143 } |
| 142 break; | 144 break; |
| 143 } | 145 } |
| 144 case kFixRate: | 146 case kFixRate: |
| 145 dict->SetString("type", "FixRate"); | 147 dict->SetString("type", "FixRate"); |
| 146 dict->SetInteger("bitrate_in_bytes_per_second", | 148 dict->SetInteger("bitrate_in_bytes_per_second", |
| 147 frame->fix_rate.bitrate.ToBytesPerSecond()); | 149 frame->fix_rate.bitrate.ToBytesPerSecond()); |
| 148 break; | 150 break; |
| 149 case kTCP: | 151 case kTCP: |
| (...skipping 26 matching lines...) Expand all Loading... |
| 176 | 178 |
| 177 base::Value* NetLogQuicWindowUpdateFrameCallback( | 179 base::Value* NetLogQuicWindowUpdateFrameCallback( |
| 178 const QuicWindowUpdateFrame* frame, | 180 const QuicWindowUpdateFrame* frame, |
| 179 NetLog::LogLevel /* log_level */) { | 181 NetLog::LogLevel /* log_level */) { |
| 180 base::DictionaryValue* dict = new base::DictionaryValue(); | 182 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 181 dict->SetInteger("stream_id", frame->stream_id); | 183 dict->SetInteger("stream_id", frame->stream_id); |
| 182 dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset)); | 184 dict->SetString("byte_offset", base::Uint64ToString(frame->byte_offset)); |
| 183 return dict; | 185 return dict; |
| 184 } | 186 } |
| 185 | 187 |
| 186 base::Value* NetLogQuicBlockedFrameCallback( | 188 base::Value* NetLogQuicBlockedFrameCallback(const QuicBlockedFrame* frame, |
| 187 const QuicBlockedFrame* frame, | 189 NetLog::LogLevel /* log_level */) { |
| 188 NetLog::LogLevel /* log_level */) { | |
| 189 base::DictionaryValue* dict = new base::DictionaryValue(); | 190 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 190 dict->SetInteger("stream_id", frame->stream_id); | 191 dict->SetInteger("stream_id", frame->stream_id); |
| 191 return dict; | 192 return dict; |
| 192 } | 193 } |
| 193 | 194 |
| 194 base::Value* NetLogQuicStopWaitingFrameCallback( | 195 base::Value* NetLogQuicStopWaitingFrameCallback( |
| 195 const QuicStopWaitingFrame* frame, | 196 const QuicStopWaitingFrame* frame, |
| 196 NetLog::LogLevel /* log_level */) { | 197 NetLog::LogLevel /* log_level */) { |
| 197 base::DictionaryValue* dict = new base::DictionaryValue(); | 198 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 198 base::DictionaryValue* sent_info = new base::DictionaryValue(); | 199 base::DictionaryValue* sent_info = new base::DictionaryValue(); |
| 199 dict->Set("sent_info", sent_info); | 200 dict->Set("sent_info", sent_info); |
| 200 sent_info->SetString("least_unacked", | 201 sent_info->SetString("least_unacked", |
| 201 base::Uint64ToString(frame->least_unacked)); | 202 base::Uint64ToString(frame->least_unacked)); |
| 202 return dict; | 203 return dict; |
| 203 } | 204 } |
| 204 | 205 |
| 205 base::Value* NetLogQuicVersionNegotiationPacketCallback( | 206 base::Value* NetLogQuicVersionNegotiationPacketCallback( |
| 206 const QuicVersionNegotiationPacket* packet, | 207 const QuicVersionNegotiationPacket* packet, |
| 207 NetLog::LogLevel /* log_level */) { | 208 NetLog::LogLevel /* log_level */) { |
| 208 base::DictionaryValue* dict = new base::DictionaryValue(); | 209 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 209 base::ListValue* versions = new base::ListValue(); | 210 base::ListValue* versions = new base::ListValue(); |
| 210 dict->Set("versions", versions); | 211 dict->Set("versions", versions); |
| 211 for (QuicVersionVector::const_iterator it = packet->versions.begin(); | 212 for (QuicVersionVector::const_iterator it = packet->versions.begin(); |
| 212 it != packet->versions.end(); ++it) { | 213 it != packet->versions.end(); |
| 214 ++it) { |
| 213 versions->AppendString(QuicVersionToString(*it)); | 215 versions->AppendString(QuicVersionToString(*it)); |
| 214 } | 216 } |
| 215 return dict; | 217 return dict; |
| 216 } | 218 } |
| 217 | 219 |
| 218 base::Value* NetLogQuicCryptoHandshakeMessageCallback( | 220 base::Value* NetLogQuicCryptoHandshakeMessageCallback( |
| 219 const CryptoHandshakeMessage* message, | 221 const CryptoHandshakeMessage* message, |
| 220 NetLog::LogLevel /* log_level */) { | 222 NetLog::LogLevel /* log_level */) { |
| 221 base::DictionaryValue* dict = new base::DictionaryValue(); | 223 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 222 dict->SetString("quic_crypto_handshake_message", message->DebugString()); | 224 dict->SetString("quic_crypto_handshake_message", message->DebugString()); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 241 void UpdatePublicResetAddressMismatchHistogram( | 243 void UpdatePublicResetAddressMismatchHistogram( |
| 242 const IPEndPoint& server_hello_address, | 244 const IPEndPoint& server_hello_address, |
| 243 const IPEndPoint& public_reset_address) { | 245 const IPEndPoint& public_reset_address) { |
| 244 int sample = GetAddressMismatch(server_hello_address, public_reset_address); | 246 int sample = GetAddressMismatch(server_hello_address, public_reset_address); |
| 245 // We are seemingly talking to an older server that does not support the | 247 // We are seemingly talking to an older server that does not support the |
| 246 // feature, so we can't report the results in the histogram. | 248 // feature, so we can't report the results in the histogram. |
| 247 if (sample < 0) { | 249 if (sample < 0) { |
| 248 return; | 250 return; |
| 249 } | 251 } |
| 250 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch", | 252 UMA_HISTOGRAM_ENUMERATION("Net.QuicSession.PublicResetAddressMismatch", |
| 251 sample, QUIC_ADDRESS_MISMATCH_MAX); | 253 sample, |
| 254 QUIC_ADDRESS_MISMATCH_MAX); |
| 252 } | 255 } |
| 253 | 256 |
| 254 const char* GetConnectionDescriptionString() { | 257 const char* GetConnectionDescriptionString() { |
| 255 NetworkChangeNotifier::ConnectionType type = | 258 NetworkChangeNotifier::ConnectionType type = |
| 256 NetworkChangeNotifier::GetConnectionType(); | 259 NetworkChangeNotifier::GetConnectionType(); |
| 257 const char* description = NetworkChangeNotifier::ConnectionTypeToString(type); | 260 const char* description = NetworkChangeNotifier::ConnectionTypeToString(type); |
| 258 // Most platforms don't distingish Wifi vs Etherenet, and call everything | 261 // Most platforms don't distingish Wifi vs Etherenet, and call everything |
| 259 // CONNECTION_UNKNOWN :-(. We'll tease out some details when we are on WiFi, | 262 // CONNECTION_UNKNOWN :-(. We'll tease out some details when we are on WiFi, |
| 260 // and hopefully leave only ethernet (with no WiFi available) in the | 263 // and hopefully leave only ethernet (with no WiFi available) in the |
| 261 // CONNECTION_UNKNOWN category. This *might* err if there is both ethernet, | 264 // CONNECTION_UNKNOWN category. This *might* err if there is both ethernet, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 289 description = "CONNECTION_WIFI_802.11n"; | 292 description = "CONNECTION_WIFI_802.11n"; |
| 290 break; | 293 break; |
| 291 case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN: | 294 case WIFI_PHY_LAYER_PROTOCOL_UNKNOWN: |
| 292 // Unclassified mode or failure to identify. | 295 // Unclassified mode or failure to identify. |
| 293 break; | 296 break; |
| 294 } | 297 } |
| 295 } | 298 } |
| 296 return description; | 299 return description; |
| 297 } | 300 } |
| 298 | 301 |
| 299 | |
| 300 } // namespace | 302 } // namespace |
| 301 | 303 |
| 302 QuicConnectionLogger::QuicConnectionLogger(const BoundNetLog& net_log) | 304 QuicConnectionLogger::QuicConnectionLogger(const BoundNetLog& net_log) |
| 303 : net_log_(net_log), | 305 : net_log_(net_log), |
| 304 last_received_packet_sequence_number_(0), | 306 last_received_packet_sequence_number_(0), |
| 305 last_received_packet_size_(0), | 307 last_received_packet_size_(0), |
| 306 largest_received_packet_sequence_number_(0), | 308 largest_received_packet_sequence_number_(0), |
| 307 largest_received_missing_packet_sequence_number_(0), | 309 largest_received_missing_packet_sequence_number_(0), |
| 308 num_out_of_order_received_packets_(0), | 310 num_out_of_order_received_packets_(0), |
| 309 num_packets_received_(0), | 311 num_packets_received_(0), |
| (...skipping 10 matching lines...) Expand all Loading... |
| 320 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent", | 322 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksSent", |
| 321 num_truncated_acks_sent_); | 323 num_truncated_acks_sent_); |
| 322 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived", | 324 UMA_HISTOGRAM_COUNTS("Net.QuicSession.TruncatedAcksReceived", |
| 323 num_truncated_acks_received_); | 325 num_truncated_acks_received_); |
| 324 if (num_frames_received_ > 0) { | 326 if (num_frames_received_ > 0) { |
| 325 int duplicate_stream_frame_per_thousand = | 327 int duplicate_stream_frame_per_thousand = |
| 326 num_duplicate_frames_received_ * 1000 / num_frames_received_; | 328 num_duplicate_frames_received_ * 1000 / num_frames_received_; |
| 327 if (num_packets_received_ < 100) { | 329 if (num_packets_received_ < 100) { |
| 328 UMA_HISTOGRAM_CUSTOM_COUNTS( | 330 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 329 "Net.QuicSession.StreamFrameDuplicatedShortConnection", | 331 "Net.QuicSession.StreamFrameDuplicatedShortConnection", |
| 330 duplicate_stream_frame_per_thousand, 1, 1000, 75); | 332 duplicate_stream_frame_per_thousand, |
| 333 1, |
| 334 1000, |
| 335 75); |
| 331 } else { | 336 } else { |
| 332 UMA_HISTOGRAM_CUSTOM_COUNTS( | 337 UMA_HISTOGRAM_CUSTOM_COUNTS( |
| 333 "Net.QuicSession.StreamFrameDuplicatedLongConnection", | 338 "Net.QuicSession.StreamFrameDuplicatedLongConnection", |
| 334 duplicate_stream_frame_per_thousand, 1, 1000, 75); | 339 duplicate_stream_frame_per_thousand, |
| 335 | 340 1, |
| 341 1000, |
| 342 75); |
| 336 } | 343 } |
| 337 } | 344 } |
| 338 | 345 |
| 339 RecordLossHistograms(); | 346 RecordLossHistograms(); |
| 340 } | 347 } |
| 341 | 348 |
| 342 void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { | 349 void QuicConnectionLogger::OnFrameAddedToPacket(const QuicFrame& frame) { |
| 343 switch (frame.type) { | 350 switch (frame.type) { |
| 344 case PADDING_FRAME: | 351 case PADDING_FRAME: |
| 345 break; | 352 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 357 break; | 364 break; |
| 358 case CONGESTION_FEEDBACK_FRAME: | 365 case CONGESTION_FEEDBACK_FRAME: |
| 359 net_log_.AddEvent( | 366 net_log_.AddEvent( |
| 360 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_SENT, | 367 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_SENT, |
| 361 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, | 368 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, |
| 362 frame.congestion_feedback_frame)); | 369 frame.congestion_feedback_frame)); |
| 363 break; | 370 break; |
| 364 case RST_STREAM_FRAME: | 371 case RST_STREAM_FRAME: |
| 365 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient", | 372 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeClient", |
| 366 frame.rst_stream_frame->error_code); | 373 frame.rst_stream_frame->error_code); |
| 367 net_log_.AddEvent( | 374 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_SENT, |
| 368 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_SENT, | 375 base::Bind(&NetLogQuicRstStreamFrameCallback, |
| 369 base::Bind(&NetLogQuicRstStreamFrameCallback, | 376 frame.rst_stream_frame)); |
| 370 frame.rst_stream_frame)); | |
| 371 break; | 377 break; |
| 372 case CONNECTION_CLOSE_FRAME: | 378 case CONNECTION_CLOSE_FRAME: |
| 373 net_log_.AddEvent( | 379 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT, |
| 374 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_SENT, | 380 base::Bind(&NetLogQuicConnectionCloseFrameCallback, |
| 375 base::Bind(&NetLogQuicConnectionCloseFrameCallback, | 381 frame.connection_close_frame)); |
| 376 frame.connection_close_frame)); | |
| 377 break; | 382 break; |
| 378 case GOAWAY_FRAME: | 383 case GOAWAY_FRAME: |
| 379 break; | 384 break; |
| 380 case WINDOW_UPDATE_FRAME: | 385 case WINDOW_UPDATE_FRAME: |
| 381 net_log_.AddEvent( | 386 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT, |
| 382 NetLog::TYPE_QUIC_SESSION_WINDOW_UPDATE_FRAME_SENT, | 387 base::Bind(&NetLogQuicWindowUpdateFrameCallback, |
| 383 base::Bind(&NetLogQuicWindowUpdateFrameCallback, | 388 frame.window_update_frame)); |
| 384 frame.window_update_frame)); | |
| 385 break; | 389 break; |
| 386 case BLOCKED_FRAME: | 390 case BLOCKED_FRAME: |
| 387 net_log_.AddEvent( | 391 net_log_.AddEvent( |
| 388 NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT, | 392 NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT, |
| 389 base::Bind(&NetLogQuicBlockedFrameCallback, | 393 base::Bind(&NetLogQuicBlockedFrameCallback, frame.blocked_frame)); |
| 390 frame.blocked_frame)); | |
| 391 break; | 394 break; |
| 392 case STOP_WAITING_FRAME: | 395 case STOP_WAITING_FRAME: |
| 393 net_log_.AddEvent( | 396 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT, |
| 394 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_SENT, | 397 base::Bind(&NetLogQuicStopWaitingFrameCallback, |
| 395 base::Bind(&NetLogQuicStopWaitingFrameCallback, | 398 frame.stop_waiting_frame)); |
| 396 frame.stop_waiting_frame)); | |
| 397 break; | 399 break; |
| 398 default: | 400 default: |
| 399 DCHECK(false) << "Illegal frame type: " << frame.type; | 401 DCHECK(false) << "Illegal frame type: " << frame.type; |
| 400 } | 402 } |
| 401 } | 403 } |
| 402 | 404 |
| 403 void QuicConnectionLogger::OnPacketSent( | 405 void QuicConnectionLogger::OnPacketSent( |
| 404 QuicPacketSequenceNumber sequence_number, | 406 QuicPacketSequenceNumber sequence_number, |
| 405 EncryptionLevel level, | 407 EncryptionLevel level, |
| 406 TransmissionType transmission_type, | 408 TransmissionType transmission_type, |
| 407 const QuicEncryptedPacket& packet, | 409 const QuicEncryptedPacket& packet, |
| 408 WriteResult result) { | 410 WriteResult result) { |
| 409 net_log_.AddEvent( | 411 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PACKET_SENT, |
| 410 NetLog::TYPE_QUIC_SESSION_PACKET_SENT, | 412 base::Bind(&NetLogQuicPacketSentCallback, |
| 411 base::Bind(&NetLogQuicPacketSentCallback, sequence_number, level, | 413 sequence_number, |
| 412 transmission_type, packet.length(), result)); | 414 level, |
| 415 transmission_type, |
| 416 packet.length(), |
| 417 result)); |
| 413 } | 418 } |
| 414 | 419 |
| 415 void QuicConnectionLogger:: OnPacketRetransmitted( | 420 void QuicConnectionLogger::OnPacketRetransmitted( |
| 416 QuicPacketSequenceNumber old_sequence_number, | 421 QuicPacketSequenceNumber old_sequence_number, |
| 417 QuicPacketSequenceNumber new_sequence_number) { | 422 QuicPacketSequenceNumber new_sequence_number) { |
| 418 net_log_.AddEvent( | 423 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED, |
| 419 NetLog::TYPE_QUIC_SESSION_PACKET_RETRANSMITTED, | 424 base::Bind(&NetLogQuicPacketRetransmittedCallback, |
| 420 base::Bind(&NetLogQuicPacketRetransmittedCallback, | 425 old_sequence_number, |
| 421 old_sequence_number, new_sequence_number)); | 426 new_sequence_number)); |
| 422 } | 427 } |
| 423 | 428 |
| 424 void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address, | 429 void QuicConnectionLogger::OnPacketReceived(const IPEndPoint& self_address, |
| 425 const IPEndPoint& peer_address, | 430 const IPEndPoint& peer_address, |
| 426 const QuicEncryptedPacket& packet) { | 431 const QuicEncryptedPacket& packet) { |
| 427 last_received_packet_size_ = packet.length(); | 432 last_received_packet_size_ = packet.length(); |
| 428 net_log_.AddEvent( | 433 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED, |
| 429 NetLog::TYPE_QUIC_SESSION_PACKET_RECEIVED, | 434 base::Bind(&NetLogQuicPacketCallback, |
| 430 base::Bind(&NetLogQuicPacketCallback, &self_address, &peer_address, | 435 &self_address, |
| 431 packet.length())); | 436 &peer_address, |
| 437 packet.length())); |
| 432 } | 438 } |
| 433 | 439 |
| 434 void QuicConnectionLogger::OnProtocolVersionMismatch( | 440 void QuicConnectionLogger::OnProtocolVersionMismatch( |
| 435 QuicVersion received_version) { | 441 QuicVersion received_version) { |
| 436 // TODO(rtenneti): Add logging. | 442 // TODO(rtenneti): Add logging. |
| 437 } | 443 } |
| 438 | 444 |
| 439 void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) { | 445 void QuicConnectionLogger::OnPacketHeader(const QuicPacketHeader& header) { |
| 440 net_log_.AddEvent( | 446 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED, |
| 441 NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_RECEIVED, | 447 base::Bind(&NetLogQuicPacketHeaderCallback, &header)); |
| 442 base::Bind(&NetLogQuicPacketHeaderCallback, &header)); | |
| 443 ++num_packets_received_; | 448 ++num_packets_received_; |
| 444 if (largest_received_packet_sequence_number_ < | 449 if (largest_received_packet_sequence_number_ < |
| 445 header.packet_sequence_number) { | 450 header.packet_sequence_number) { |
| 446 QuicPacketSequenceNumber delta = header.packet_sequence_number - | 451 QuicPacketSequenceNumber delta = header.packet_sequence_number - |
| 447 largest_received_packet_sequence_number_; | 452 largest_received_packet_sequence_number_; |
| 448 if (delta > 1) { | 453 if (delta > 1) { |
| 449 // There is a gap between the largest packet previously received and | 454 // There is a gap between the largest packet previously received and |
| 450 // the current packet. This indicates either loss, or out-of-order | 455 // the current packet. This indicates either loss, or out-of-order |
| 451 // delivery. | 456 // delivery. |
| 452 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", delta - 1); | 457 UMA_HISTOGRAM_COUNTS("Net.QuicSession.PacketGapReceived", delta - 1); |
| 453 } | 458 } |
| 454 largest_received_packet_sequence_number_ = header.packet_sequence_number; | 459 largest_received_packet_sequence_number_ = header.packet_sequence_number; |
| 455 } | 460 } |
| 456 if (header.packet_sequence_number < received_packets_.size()) | 461 if (header.packet_sequence_number < received_packets_.size()) |
| 457 received_packets_[header.packet_sequence_number] = true; | 462 received_packets_[header.packet_sequence_number] = true; |
| 458 if (header.packet_sequence_number < last_received_packet_sequence_number_) { | 463 if (header.packet_sequence_number < last_received_packet_sequence_number_) { |
| 459 ++num_out_of_order_received_packets_; | 464 ++num_out_of_order_received_packets_; |
| 460 UMA_HISTOGRAM_COUNTS("Net.QuicSession.OutOfOrderGapReceived", | 465 UMA_HISTOGRAM_COUNTS( |
| 461 last_received_packet_sequence_number_ - | 466 "Net.QuicSession.OutOfOrderGapReceived", |
| 462 header.packet_sequence_number); | 467 last_received_packet_sequence_number_ - header.packet_sequence_number); |
| 463 } | 468 } |
| 464 last_received_packet_sequence_number_ = header.packet_sequence_number; | 469 last_received_packet_sequence_number_ = header.packet_sequence_number; |
| 465 } | 470 } |
| 466 | 471 |
| 467 void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame& frame) { | 472 void QuicConnectionLogger::OnStreamFrame(const QuicStreamFrame& frame) { |
| 468 net_log_.AddEvent( | 473 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED, |
| 469 NetLog::TYPE_QUIC_SESSION_STREAM_FRAME_RECEIVED, | 474 base::Bind(&NetLogQuicStreamFrameCallback, &frame)); |
| 470 base::Bind(&NetLogQuicStreamFrameCallback, &frame)); | |
| 471 } | 475 } |
| 472 | 476 |
| 473 void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) { | 477 void QuicConnectionLogger::OnAckFrame(const QuicAckFrame& frame) { |
| 474 net_log_.AddEvent( | 478 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED, |
| 475 NetLog::TYPE_QUIC_SESSION_ACK_FRAME_RECEIVED, | 479 base::Bind(&NetLogQuicAckFrameCallback, &frame)); |
| 476 base::Bind(&NetLogQuicAckFrameCallback, &frame)); | |
| 477 | 480 |
| 478 const size_t kApproximateLargestSoloAckBytes = 100; | 481 const size_t kApproximateLargestSoloAckBytes = 100; |
| 479 if (last_received_packet_sequence_number_ < received_acks_.size() && | 482 if (last_received_packet_sequence_number_ < received_acks_.size() && |
| 480 last_received_packet_size_ < kApproximateLargestSoloAckBytes) | 483 last_received_packet_size_ < kApproximateLargestSoloAckBytes) |
| 481 received_acks_[last_received_packet_sequence_number_] = true; | 484 received_acks_[last_received_packet_sequence_number_] = true; |
| 482 | 485 |
| 483 if (frame.received_info.is_truncated) | 486 if (frame.received_info.is_truncated) |
| 484 ++num_truncated_acks_received_; | 487 ++num_truncated_acks_received_; |
| 485 | 488 |
| 486 if (frame.received_info.missing_packets.empty()) | 489 if (frame.received_info.missing_packets.empty()) |
| (...skipping 21 matching lines...) Expand all Loading... |
| 508 UpdatePacketGapSentHistogram(num_consecutive_missing_packets); | 511 UpdatePacketGapSentHistogram(num_consecutive_missing_packets); |
| 509 // Make sure this packet it included in the count. | 512 // Make sure this packet it included in the count. |
| 510 num_consecutive_missing_packets = 1; | 513 num_consecutive_missing_packets = 1; |
| 511 } | 514 } |
| 512 previous_missing_packet = *it; | 515 previous_missing_packet = *it; |
| 513 ++it; | 516 ++it; |
| 514 } | 517 } |
| 515 if (num_consecutive_missing_packets != 0) { | 518 if (num_consecutive_missing_packets != 0) { |
| 516 UpdatePacketGapSentHistogram(num_consecutive_missing_packets); | 519 UpdatePacketGapSentHistogram(num_consecutive_missing_packets); |
| 517 } | 520 } |
| 518 largest_received_missing_packet_sequence_number_ = | 521 largest_received_missing_packet_sequence_number_ = *missing_packets.rbegin(); |
| 519 *missing_packets.rbegin(); | |
| 520 } | 522 } |
| 521 | 523 |
| 522 void QuicConnectionLogger::OnCongestionFeedbackFrame( | 524 void QuicConnectionLogger::OnCongestionFeedbackFrame( |
| 523 const QuicCongestionFeedbackFrame& frame) { | 525 const QuicCongestionFeedbackFrame& frame) { |
| 524 net_log_.AddEvent( | 526 net_log_.AddEvent( |
| 525 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_RECEIVED, | 527 NetLog::TYPE_QUIC_SESSION_CONGESTION_FEEDBACK_FRAME_RECEIVED, |
| 526 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, &frame)); | 528 base::Bind(&NetLogQuicCongestionFeedbackFrameCallback, &frame)); |
| 527 } | 529 } |
| 528 | 530 |
| 529 void QuicConnectionLogger::OnStopWaitingFrame( | 531 void QuicConnectionLogger::OnStopWaitingFrame( |
| 530 const QuicStopWaitingFrame& frame) { | 532 const QuicStopWaitingFrame& frame) { |
| 531 net_log_.AddEvent( | 533 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED, |
| 532 NetLog::TYPE_QUIC_SESSION_STOP_WAITING_FRAME_RECEIVED, | 534 base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame)); |
| 533 base::Bind(&NetLogQuicStopWaitingFrameCallback, &frame)); | |
| 534 } | 535 } |
| 535 | 536 |
| 536 void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) { | 537 void QuicConnectionLogger::OnRstStreamFrame(const QuicRstStreamFrame& frame) { |
| 537 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer", | 538 UMA_HISTOGRAM_SPARSE_SLOWLY("Net.QuicSession.RstStreamErrorCodeServer", |
| 538 frame.error_code); | 539 frame.error_code); |
| 539 net_log_.AddEvent( | 540 net_log_.AddEvent(NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_RECEIVED, |
| 540 NetLog::TYPE_QUIC_SESSION_RST_STREAM_FRAME_RECEIVED, | 541 base::Bind(&NetLogQuicRstStreamFrameCallback, &frame)); |
| 541 base::Bind(&NetLogQuicRstStreamFrameCallback, &frame)); | |
| 542 } | 542 } |
| 543 | 543 |
| 544 void QuicConnectionLogger::OnConnectionCloseFrame( | 544 void QuicConnectionLogger::OnConnectionCloseFrame( |
| 545 const QuicConnectionCloseFrame& frame) { | 545 const QuicConnectionCloseFrame& frame) { |
| 546 net_log_.AddEvent( | 546 net_log_.AddEvent( |
| 547 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED, | 547 NetLog::TYPE_QUIC_SESSION_CONNECTION_CLOSE_FRAME_RECEIVED, |
| 548 base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame)); | 548 base::Bind(&NetLogQuicConnectionCloseFrameCallback, &frame)); |
| 549 } | 549 } |
| 550 | 550 |
| 551 void QuicConnectionLogger::OnPublicResetPacket( | 551 void QuicConnectionLogger::OnPublicResetPacket( |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 num_frames_received_ += num_frames_received; | 615 num_frames_received_ += num_frames_received; |
| 616 num_duplicate_frames_received_ += num_duplicate_frames_received; | 616 num_duplicate_frames_received_ += num_duplicate_frames_received; |
| 617 } | 617 } |
| 618 } | 618 } |
| 619 | 619 |
| 620 base::HistogramBase* QuicConnectionLogger::GetPacketSequenceNumberHistogram( | 620 base::HistogramBase* QuicConnectionLogger::GetPacketSequenceNumberHistogram( |
| 621 const char* statistic_name) const { | 621 const char* statistic_name) const { |
| 622 string prefix("Net.QuicSession.PacketReceived_"); | 622 string prefix("Net.QuicSession.PacketReceived_"); |
| 623 return base::LinearHistogram::FactoryGet( | 623 return base::LinearHistogram::FactoryGet( |
| 624 prefix + statistic_name + connection_description_, | 624 prefix + statistic_name + connection_description_, |
| 625 1, received_packets_.size(), received_packets_.size() + 1, | 625 1, |
| 626 received_packets_.size(), |
| 627 received_packets_.size() + 1, |
| 626 base::HistogramBase::kUmaTargetedHistogramFlag); | 628 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 627 } | 629 } |
| 628 | 630 |
| 629 base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram( | 631 base::HistogramBase* QuicConnectionLogger::Get6PacketHistogram( |
| 630 const char* which_6) const { | 632 const char* which_6) const { |
| 631 // This histogram takes a binary encoding of the 6 consecutive packets | 633 // This histogram takes a binary encoding of the 6 consecutive packets |
| 632 // received. As a result, there are 64 possible sample-patterns. | 634 // received. As a result, there are 64 possible sample-patterns. |
| 633 string prefix("Net.QuicSession.6PacketsPatternsReceived_"); | 635 string prefix("Net.QuicSession.6PacketsPatternsReceived_"); |
| 634 return base::LinearHistogram::FactoryGet( | 636 return base::LinearHistogram::FactoryGet( |
| 635 prefix + which_6 + connection_description_, 1, 64, 65, | 637 prefix + which_6 + connection_description_, |
| 638 1, |
| 639 64, |
| 640 65, |
| 636 base::HistogramBase::kUmaTargetedHistogramFlag); | 641 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 637 } | 642 } |
| 638 | 643 |
| 639 base::HistogramBase* QuicConnectionLogger::Get21CumulativeHistogram( | 644 base::HistogramBase* QuicConnectionLogger::Get21CumulativeHistogram( |
| 640 const char* which_21) const { | 645 const char* which_21) const { |
| 641 // This histogram contains, for each sequence of 21 packets, the results from | 646 // This histogram contains, for each sequence of 21 packets, the results from |
| 642 // 21 distinct questions about that sequence. Conceptually the histogtram is | 647 // 21 distinct questions about that sequence. Conceptually the histogtram is |
| 643 // broken into 21 distinct ranges, and one sample is added into each of those | 648 // broken into 21 distinct ranges, and one sample is added into each of those |
| 644 // ranges whenever we process a set of 21 packets. | 649 // ranges whenever we process a set of 21 packets. |
| 645 // There is a little rendundancy, as each "range" must have the same number | 650 // There is a little rendundancy, as each "range" must have the same number |
| 646 // of samples, all told, but the histogram is a tad easier to read this way. | 651 // of samples, all told, but the histogram is a tad easier to read this way. |
| 647 // The questions are: | 652 // The questions are: |
| 648 // Was the first packet present (bucket 0==>no; bucket 1==>yes) | 653 // Was the first packet present (bucket 0==>no; bucket 1==>yes) |
| 649 // Of the first two packets, how many were present? (bucket 2==> none; | 654 // Of the first two packets, how many were present? (bucket 2==> none; |
| 650 // bucket 3==> 1 of 2; bucket 4==> 2 of 2) | 655 // bucket 3==> 1 of 2; bucket 4==> 2 of 2) |
| 651 // Of the first three packets, how many were present? (bucket 5==>none; | 656 // Of the first three packets, how many were present? (bucket 5==>none; |
| 652 // bucket 6==> 1 of 3; bucket 7==> 2 of 3; bucket 8==> 3 of 3). | 657 // bucket 6==> 1 of 3; bucket 7==> 2 of 3; bucket 8==> 3 of 3). |
| 653 // etc. | 658 // etc. |
| 654 string prefix("Net.QuicSession.21CumulativePacketsReceived_"); | 659 string prefix("Net.QuicSession.21CumulativePacketsReceived_"); |
| 655 return base::LinearHistogram::FactoryGet( | 660 return base::LinearHistogram::FactoryGet( |
| 656 prefix + which_21 + connection_description_, | 661 prefix + which_21 + connection_description_, |
| 657 1, kBoundingSampleInCumulativeHistogram, | 662 1, |
| 663 kBoundingSampleInCumulativeHistogram, |
| 658 kBoundingSampleInCumulativeHistogram + 1, | 664 kBoundingSampleInCumulativeHistogram + 1, |
| 659 base::HistogramBase::kUmaTargetedHistogramFlag); | 665 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 660 } | 666 } |
| 661 | 667 |
| 662 // static | 668 // static |
| 663 void QuicConnectionLogger::AddTo21CumulativeHistogram( | 669 void QuicConnectionLogger::AddTo21CumulativeHistogram( |
| 664 base::HistogramBase* histogram, | 670 base::HistogramBase* histogram, |
| 665 int bit_mask_of_packets, | 671 int bit_mask_of_packets, |
| 666 int valid_bits_in_mask) { | 672 int valid_bits_in_mask) { |
| 667 DCHECK_LE(valid_bits_in_mask, 21); | 673 DCHECK_LE(valid_bits_in_mask, 21); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 691 return; | 697 return; |
| 692 | 698 |
| 693 QuicPacketSequenceNumber divisor = largest_received_packet_sequence_number_; | 699 QuicPacketSequenceNumber divisor = largest_received_packet_sequence_number_; |
| 694 QuicPacketSequenceNumber numerator = divisor - num_packets_received_; | 700 QuicPacketSequenceNumber numerator = divisor - num_packets_received_; |
| 695 if (divisor < 100000) | 701 if (divisor < 100000) |
| 696 numerator *= 1000; | 702 numerator *= 1000; |
| 697 else | 703 else |
| 698 divisor /= 1000; | 704 divisor /= 1000; |
| 699 string prefix("Net.QuicSession.PacketLossRate_"); | 705 string prefix("Net.QuicSession.PacketLossRate_"); |
| 700 base::HistogramBase* histogram = base::Histogram::FactoryGet( | 706 base::HistogramBase* histogram = base::Histogram::FactoryGet( |
| 701 prefix + connection_description_, 1, 1000, 75, | 707 prefix + connection_description_, |
| 708 1, |
| 709 1000, |
| 710 75, |
| 702 base::HistogramBase::kUmaTargetedHistogramFlag); | 711 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 703 histogram->Add(numerator / divisor); | 712 histogram->Add(numerator / divisor); |
| 704 } | 713 } |
| 705 | 714 |
| 706 void QuicConnectionLogger::RecordLossHistograms() const { | 715 void QuicConnectionLogger::RecordLossHistograms() const { |
| 707 if (largest_received_packet_sequence_number_ == 0) | 716 if (largest_received_packet_sequence_number_ == 0) |
| 708 return; // Connection was never used. | 717 return; // Connection was never used. |
| 709 RecordAggregatePacketLossRate(); | 718 RecordAggregatePacketLossRate(); |
| 710 | 719 |
| 711 base::HistogramBase* is_not_ack_histogram = | 720 base::HistogramBase* is_not_ack_histogram = |
| 712 GetPacketSequenceNumberHistogram("IsNotAck_"); | 721 GetPacketSequenceNumberHistogram("IsNotAck_"); |
| 713 base::HistogramBase* is_an_ack_histogram = | 722 base::HistogramBase* is_an_ack_histogram = |
| 714 GetPacketSequenceNumberHistogram("IsAnAck_"); | 723 GetPacketSequenceNumberHistogram("IsAnAck_"); |
| 715 base::HistogramBase* packet_arrived_histogram = | 724 base::HistogramBase* packet_arrived_histogram = |
| 716 GetPacketSequenceNumberHistogram("Ack_"); | 725 GetPacketSequenceNumberHistogram("Ack_"); |
| 717 base::HistogramBase* packet_missing_histogram = | 726 base::HistogramBase* packet_missing_histogram = |
| 718 GetPacketSequenceNumberHistogram("Nack_"); | 727 GetPacketSequenceNumberHistogram("Nack_"); |
| 719 base::HistogramBase* ongoing_cumulative_packet_histogram = | 728 base::HistogramBase* ongoing_cumulative_packet_histogram = |
| 720 Get21CumulativeHistogram("Some21s_"); | 729 Get21CumulativeHistogram("Some21s_"); |
| 721 base::HistogramBase* first_cumulative_packet_histogram = | 730 base::HistogramBase* first_cumulative_packet_histogram = |
| 722 Get21CumulativeHistogram("First21_"); | 731 Get21CumulativeHistogram("First21_"); |
| 723 base::HistogramBase* six_packet_histogram = Get6PacketHistogram("Some6s_"); | 732 base::HistogramBase* six_packet_histogram = Get6PacketHistogram("Some6s_"); |
| 724 | 733 |
| 725 DCHECK_EQ(received_packets_.size(), received_acks_.size()); | 734 DCHECK_EQ(received_packets_.size(), received_acks_.size()); |
| 726 const QuicPacketSequenceNumber last_index = | 735 const QuicPacketSequenceNumber last_index = |
| 727 std::min<QuicPacketSequenceNumber>(received_packets_.size() - 1, | 736 std::min<QuicPacketSequenceNumber>( |
| 737 received_packets_.size() - 1, |
| 728 largest_received_packet_sequence_number_); | 738 largest_received_packet_sequence_number_); |
| 729 const QuicPacketSequenceNumber index_of_first_21_contribution = | 739 const QuicPacketSequenceNumber index_of_first_21_contribution = |
| 730 std::min<QuicPacketSequenceNumber>(21, last_index); | 740 std::min<QuicPacketSequenceNumber>(21, last_index); |
| 731 // Bit pattern of consecutively received packets that is maintained as we scan | 741 // Bit pattern of consecutively received packets that is maintained as we scan |
| 732 // through the received_packets_ vector. Less significant bits correspond to | 742 // through the received_packets_ vector. Less significant bits correspond to |
| 733 // less recent packets, and only the low order 21 bits are ever defined. | 743 // less recent packets, and only the low order 21 bits are ever defined. |
| 734 // Bit is 1 iff corresponding packet was received. | 744 // Bit is 1 iff corresponding packet was received. |
| 735 int packet_pattern_21 = 0; | 745 int packet_pattern_21 = 0; |
| 736 // Zero is an invalid packet sequence number. | 746 // Zero is an invalid packet sequence number. |
| 737 DCHECK(!received_packets_[0]); | 747 DCHECK(!received_packets_[0]); |
| 738 for (size_t i = 1; i <= last_index; ++i) { | 748 for (size_t i = 1; i <= last_index; ++i) { |
| 739 if (received_acks_[i]) | 749 if (received_acks_[i]) |
| 740 is_an_ack_histogram->Add(i); | 750 is_an_ack_histogram->Add(i); |
| 741 else | 751 else |
| 742 is_not_ack_histogram->Add(i); | 752 is_not_ack_histogram->Add(i); |
| 743 | 753 |
| 744 packet_pattern_21 >>= 1; | 754 packet_pattern_21 >>= 1; |
| 745 if (received_packets_[i]) { | 755 if (received_packets_[i]) { |
| 746 packet_arrived_histogram->Add(i); | 756 packet_arrived_histogram->Add(i); |
| 747 packet_pattern_21 |= (1 << 20); // Turn on the 21st bit. | 757 packet_pattern_21 |= (1 << 20); // Turn on the 21st bit. |
| 748 } else { | 758 } else { |
| 749 packet_missing_histogram->Add(i); | 759 packet_missing_histogram->Add(i); |
| 750 } | 760 } |
| 751 | 761 |
| 752 if (i == index_of_first_21_contribution) { | 762 if (i == index_of_first_21_contribution) { |
| 753 AddTo21CumulativeHistogram(first_cumulative_packet_histogram, | 763 AddTo21CumulativeHistogram( |
| 754 packet_pattern_21, i); | 764 first_cumulative_packet_histogram, packet_pattern_21, i); |
| 755 } | 765 } |
| 756 // We'll just record for non-overlapping ranges, to reduce histogramming | 766 // We'll just record for non-overlapping ranges, to reduce histogramming |
| 757 // cost for now. Each call does 21 separate histogram additions. | 767 // cost for now. Each call does 21 separate histogram additions. |
| 758 if (i > 21 || i % 21 == 0) { | 768 if (i > 21 || i % 21 == 0) { |
| 759 AddTo21CumulativeHistogram(ongoing_cumulative_packet_histogram, | 769 AddTo21CumulativeHistogram( |
| 760 packet_pattern_21, 21); | 770 ongoing_cumulative_packet_histogram, packet_pattern_21, 21); |
| 761 } | 771 } |
| 762 | 772 |
| 763 if (i < 6) | 773 if (i < 6) |
| 764 continue; // Not enough packets to do any pattern recording. | 774 continue; // Not enough packets to do any pattern recording. |
| 765 int recent_6_mask = packet_pattern_21 >> 15; | 775 int recent_6_mask = packet_pattern_21 >> 15; |
| 766 DCHECK_LT(recent_6_mask, 64); | 776 DCHECK_LT(recent_6_mask, 64); |
| 767 if (i == 6) { | 777 if (i == 6) { |
| 768 Get6PacketHistogram("First6_")->Add(recent_6_mask); | 778 Get6PacketHistogram("First6_")->Add(recent_6_mask); |
| 769 continue; | 779 continue; |
| 770 } | 780 } |
| 771 // Record some overlapping patterns, to get a better picture, since this is | 781 // Record some overlapping patterns, to get a better picture, since this is |
| 772 // not very expensive. | 782 // not very expensive. |
| 773 if (i % 3 == 0) | 783 if (i % 3 == 0) |
| 774 six_packet_histogram->Add(recent_6_mask); | 784 six_packet_histogram->Add(recent_6_mask); |
| 775 } | 785 } |
| 776 } | 786 } |
| 777 | 787 |
| 778 } // namespace net | 788 } // namespace net |
| OLD | NEW |