• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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