1 // Copyright (c) 2010 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/socket/client_socket.h"
6
7 #include "base/metrics/field_trial.h"
8 #include "base/metrics/histogram.h"
9 #include "base/string_number_conversions.h"
10 #include "base/values.h"
11
12 namespace net {
13
14 namespace {
15
16 // Parameters for SOCKET_BYTES_RECEIVED and SOCKET_BYTES_SENT events.
17 // Includes bytes transferred and, if |bytes| is not NULL, the bytes themselves.
18 class NetLogBytesTransferredParameter : public NetLog::EventParameters {
19 public:
20 NetLogBytesTransferredParameter(int byte_count, const char* bytes);
21
22 virtual Value* ToValue() const;
23
24 private:
25 const int byte_count_;
26 std::string hex_encoded_bytes_;
27 bool has_bytes_;
28 };
29
NetLogBytesTransferredParameter(int byte_count,const char * transferred_bytes)30 NetLogBytesTransferredParameter::NetLogBytesTransferredParameter(
31 int byte_count, const char* transferred_bytes)
32 : byte_count_(byte_count),
33 has_bytes_(false) {
34 if (transferred_bytes) {
35 hex_encoded_bytes_ = base::HexEncode(transferred_bytes, byte_count);
36 has_bytes_ = true;
37 }
38 }
39
ToValue() const40 Value* NetLogBytesTransferredParameter::ToValue() const {
41 DictionaryValue* dict = new DictionaryValue();
42 dict->SetInteger("byte_count", byte_count_);
43 if (has_bytes_)
44 dict->SetString("hex_encoded_bytes", hex_encoded_bytes_);
45 return dict;
46 }
47
48 } // namespace
49
UseHistory()50 ClientSocket::UseHistory::UseHistory()
51 : was_ever_connected_(false),
52 was_used_to_convey_data_(false),
53 omnibox_speculation_(false),
54 subresource_speculation_(false) {
55 }
56
~UseHistory()57 ClientSocket::UseHistory::~UseHistory() {
58 EmitPreconnectionHistograms();
59 }
60
Reset()61 void ClientSocket::UseHistory::Reset() {
62 EmitPreconnectionHistograms();
63 was_ever_connected_ = false;
64 was_used_to_convey_data_ = false;
65 // omnibox_speculation_ and subresource_speculation_ values
66 // are intentionally preserved.
67 }
68
set_was_ever_connected()69 void ClientSocket::UseHistory::set_was_ever_connected() {
70 DCHECK(!was_used_to_convey_data_);
71 was_ever_connected_ = true;
72 }
73
set_was_used_to_convey_data()74 void ClientSocket::UseHistory::set_was_used_to_convey_data() {
75 DCHECK(was_ever_connected_);
76 was_used_to_convey_data_ = true;
77 }
78
79
set_subresource_speculation()80 void ClientSocket::UseHistory::set_subresource_speculation() {
81 DCHECK(was_ever_connected_);
82 // TODO(jar): We should transition to marking a socket (or stream) at
83 // construction time as being created for speculative reasons. This current
84 // approach of trying to track use of a socket to convey data can make
85 // mistakes when other sockets (such as ones sitting in the pool for a long
86 // time) are issued. Unused sockets can be left over when a when a set of
87 // connections to a host are made, and one is "unlucky" and takes so long to
88 // complete a connection, that another socket is used, and recycled before a
89 // second connection comes available. Similarly, re-try connections can leave
90 // an original (slow to connect socket) in the pool, and that can be issued
91 // to a speculative requester. In any cases such old sockets will fail when an
92 // attempt is made to used them!... and then it will look like a speculative
93 // socket was discarded without any user!?!?!
94 if (was_used_to_convey_data_)
95 return;
96 subresource_speculation_ = true;
97 }
98
set_omnibox_speculation()99 void ClientSocket::UseHistory::set_omnibox_speculation() {
100 DCHECK(was_ever_connected_);
101 if (was_used_to_convey_data_)
102 return;
103 omnibox_speculation_ = true;
104 }
105
was_used_to_convey_data() const106 bool ClientSocket::UseHistory::was_used_to_convey_data() const {
107 DCHECK(!was_used_to_convey_data_ || was_ever_connected_);
108 return was_used_to_convey_data_;
109 }
110
EmitPreconnectionHistograms() const111 void ClientSocket::UseHistory::EmitPreconnectionHistograms() const {
112 DCHECK(!subresource_speculation_ || !omnibox_speculation_);
113 // 0 ==> non-speculative, never connected.
114 // 1 ==> non-speculative never used (but connected).
115 // 2 ==> non-speculative and used.
116 // 3 ==> omnibox_speculative never connected.
117 // 4 ==> omnibox_speculative never used (but connected).
118 // 5 ==> omnibox_speculative and used.
119 // 6 ==> subresource_speculative never connected.
120 // 7 ==> subresource_speculative never used (but connected).
121 // 8 ==> subresource_speculative and used.
122 int result;
123 if (was_used_to_convey_data_)
124 result = 2;
125 else if (was_ever_connected_)
126 result = 1;
127 else
128 result = 0; // Never used, and not really connected.
129
130 if (omnibox_speculation_)
131 result += 3;
132 else if (subresource_speculation_)
133 result += 6;
134 UMA_HISTOGRAM_ENUMERATION("Net.PreconnectUtilization2", result, 9);
135
136 static const bool connect_backup_jobs_fieldtrial =
137 base::FieldTrialList::Find("ConnnectBackupJobs") &&
138 !base::FieldTrialList::Find("ConnnectBackupJobs")->group_name().empty();
139 if (connect_backup_jobs_fieldtrial) {
140 UMA_HISTOGRAM_ENUMERATION(
141 base::FieldTrial::MakeName("Net.PreconnectUtilization2",
142 "ConnnectBackupJobs"),
143 result, 9);
144 }
145 }
146
LogByteTransfer(const BoundNetLog & net_log,NetLog::EventType event_type,int byte_count,char * bytes) const147 void ClientSocket::LogByteTransfer(const BoundNetLog& net_log,
148 NetLog::EventType event_type,
149 int byte_count,
150 char* bytes) const {
151 scoped_refptr<NetLog::EventParameters> params;
152 if (net_log.IsLoggingBytes()) {
153 params = new NetLogBytesTransferredParameter(byte_count, bytes);
154 } else {
155 params = new NetLogBytesTransferredParameter(byte_count, NULL);
156 }
157 net_log.AddEvent(event_type, params);
158 }
159
160 } // namespace net
161