Home | History | Annotate | Download | only in socket
      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 
     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 
     40 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 
     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 
     57 ClientSocket::UseHistory::~UseHistory() {
     58   EmitPreconnectionHistograms();
     59 }
     60 
     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 
     69 void ClientSocket::UseHistory::set_was_ever_connected() {
     70   DCHECK(!was_used_to_convey_data_);
     71   was_ever_connected_ = true;
     72 }
     73 
     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 
     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 
     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 
    106 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 
    111 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 
    147 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